1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2008-2013. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: %%
   21: -module(public_key_SUITE).
   22: 
   23: -include_lib("common_test/include/ct.hrl").
   24: -include_lib("public_key/include/public_key.hrl").
   25: 
   26: %% Note: This directive should only be used in test suites.
   27: -compile(export_all).
   28: 
   29: -define(TIMEOUT, 120000). % 2 min
   30: 
   31: 
   32: %%--------------------------------------------------------------------
   33: %% Common Test interface functions -----------------------------------
   34: %%--------------------------------------------------------------------
   35: 
   36: suite() -> [{ct_hooks,[ts_install_cth]}].
   37: 
   38: all() -> 
   39:     [app,
   40:      {group, pem_decode_encode},
   41:      {group, ssh_public_key_decode_encode},
   42:      encrypt_decrypt,
   43:      {group, sign_verify},
   44:      pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
   45:      pkix_iso_rsa_oid, pkix_iso_dsa_oid].
   46: 
   47: groups() -> 
   48:     [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem,
   49: 			      dh_pem, cert_pem, pkcs7_pem, pkcs10_pem]},
   50:      {ssh_public_key_decode_encode, [],
   51:       [ssh_rsa_public_key, ssh_dsa_public_key, ssh_rfc4716_rsa_comment,
   52:        ssh_rfc4716_dsa_comment, ssh_rfc4716_rsa_subject, ssh_known_hosts,
   53:        ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment,
   54:        ssh_openssh_public_key_long_header]},
   55:      {sign_verify, [], [rsa_sign_verify, dsa_sign_verify]}
   56:     ].
   57: %%-------------------------------------------------------------------
   58: init_per_suite(Config) ->
   59:     application:stop(crypto),
   60:     try crypto:start() of
   61: 	ok ->
   62: 	    application:start(asn1),
   63: 	    Config
   64:     catch _:_ ->
   65: 	    {skip, "Crypto did not start"}
   66:     end.
   67: 
   68: end_per_suite(_Config) ->
   69:     application:stop(asn1),
   70:     application:stop(crypto).
   71: 
   72: %%-------------------------------------------------------------------
   73: init_per_group(_GroupName, Config) ->
   74:     Config.
   75: 
   76: end_per_group(_GroupName, Config) ->
   77:     Config.
   78: %%-------------------------------------------------------------------
   79: init_per_testcase(_TestCase, Config0) ->
   80:     Config = lists:keydelete(watchdog, 1, Config0),
   81:     Dog = ct:timetrap(?TIMEOUT),
   82:     [{watchdog, Dog} | Config].
   83: 
   84: 
   85: end_per_testcase(_TestCase, _Config) ->
   86:     ok.
   87: %%--------------------------------------------------------------------
   88: %% Test Cases --------------------------------------------------------
   89: %%--------------------------------------------------------------------
   90: 
   91: app() ->
   92:     [{doc, "Test that the public_key app file is ok"}].
   93: app(Config) when is_list(Config) ->
   94:     ok = ?t:app_test(public_key).
   95: 
   96: %%--------------------------------------------------------------------
   97: 
   98: dsa_pem() ->
   99:     [{doc, "DSA PEM-file decode/encode"}].
  100: dsa_pem(Config) when is_list(Config) ->
  101:     Datadir = ?config(data_dir, Config),
  102: 
  103:      [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] =
  104: 	erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")),
  105: 
  106:     DSAKey = public_key:der_decode('DSAPrivateKey', DerDSAKey),
  107: 
  108:     DSAKey = public_key:pem_entry_decode(Entry0),
  109: 
  110:     {ok, DSAPubPem} = file:read_file(filename:join(Datadir, "dsa_pub.pem")),
  111:     [{'SubjectPublicKeyInfo', _, _} = PubEntry0] =
  112:         public_key:pem_decode(DSAPubPem),
  113:     DSAPubKey = public_key:pem_entry_decode(PubEntry0),
  114:     true = check_entry_type(DSAPubKey, 'DSAPublicKey'),
  115:     PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', DSAPubKey),
  116:     DSAPubPemNoEndNewLines = strip_ending_newlines(DSAPubPem),
  117:     DSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])).
  118: 
  119: %%--------------------------------------------------------------------
  120: 
  121: rsa_pem() ->
  122:     [{doc, "RSA PEM-file decode/encode"}].
  123: rsa_pem(Config) when is_list(Config) ->
  124:     Datadir = ?config(data_dir, Config),
  125:     [{'RSAPrivateKey', DerRSAKey, not_encrypted} =  Entry0 ] =
  126: 	erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
  127: 
  128:     RSAKey0 = public_key:der_decode('RSAPrivateKey', DerRSAKey),
  129: 
  130:     RSAKey0 = public_key:pem_entry_decode(Entry0),
  131:     
  132:     [{'RSAPrivateKey', _, {_,_}} = Entry1] =
  133: 	erl_make_certs:pem_to_der(filename:join(Datadir, "rsa.pem")),
  134: 
  135:     true = check_entry_type(public_key:pem_entry_decode(Entry1, "abcd1234"),
  136: 			    'RSAPrivateKey'),
  137: 
  138:     {ok, RSAPubPem} = file:read_file(filename:join(Datadir, "rsa_pub.pem")),
  139:     [{'SubjectPublicKeyInfo', _, _} = PubEntry0] =
  140:         public_key:pem_decode(RSAPubPem),
  141:     RSAPubKey = public_key:pem_entry_decode(PubEntry0),
  142:     true = check_entry_type(RSAPubKey, 'RSAPublicKey'),
  143:     PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey),
  144:     RSAPubPemNoEndNewLines = strip_ending_newlines(RSAPubPem),
  145:     RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])),
  146: 
  147:     {ok, RSARawPem} = file:read_file(filename:join(Datadir, "rsa_pub_key.pem")),
  148:     [{'RSAPublicKey', _, _} = PubEntry1] =
  149:         public_key:pem_decode(RSARawPem),
  150:     RSAPubKey = public_key:pem_entry_decode(PubEntry1),
  151:     RSARawPemNoEndNewLines = strip_ending_newlines(RSARawPem),
  152:     RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])).
  153: 
  154: %%--------------------------------------------------------------------
  155: 
  156: encrypted_pem() ->
  157:     [{doc, "Encrypted PEM-file decode/encode"}].
  158: encrypted_pem(Config) when is_list(Config) ->
  159:     Datadir = ?config(data_dir, Config),
  160: 
  161:     [{'RSAPrivateKey', DerRSAKey, not_encrypted}] =
  162: 	erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
  163: 
  164:     RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey),
  165: 
  166:     Salt0 = crypto:rand_bytes(8),
  167:     Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
  168: 					 {{"DES-EDE3-CBC", Salt0}, "1234abcd"}),
  169:     RSAKey = public_key:pem_entry_decode(Entry0,"1234abcd"),
  170:     Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"),
  171:     erl_make_certs:der_to_pem(Des3KeyFile, [Entry0]),
  172:     [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] =
  173: 	erl_make_certs:pem_to_der(Des3KeyFile),
  174: 
  175:     Salt1 = crypto:rand_bytes(8),
  176:     Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
  177: 					   {{"DES-CBC", Salt1}, "4567efgh"}),
  178:     DesKeyFile = filename:join(Datadir, "des_client_key.pem"),
  179:     erl_make_certs:der_to_pem(DesKeyFile, [Entry1]),
  180:     [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] =
  181: 	erl_make_certs:pem_to_der(DesKeyFile),
  182:     true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"),
  183: 			     'RSAPrivateKey').
  184:     
  185: %%--------------------------------------------------------------------
  186: 
  187: dh_pem() ->
  188:     [{doc, "DH parametrs PEM-file decode/encode"}].
  189: dh_pem(Config) when is_list(Config) ->
  190:     Datadir = ?config(data_dir, Config),
  191:     [{'DHParameter', _DerDH, not_encrypted} = Entry] =
  192: 	erl_make_certs:pem_to_der(filename:join(Datadir, "dh.pem")),
  193:     asn1_encode_decode(Entry).
  194: 
  195: %%--------------------------------------------------------------------
  196: 
  197: pkcs10_pem() ->
  198:    [{doc, "PKCS-10 PEM-file decode/encode"}].
  199: pkcs10_pem(Config) when is_list(Config) ->
  200:     Datadir = ?config(data_dir, Config),
  201:     [{'CertificationRequest', _DerPKCS10, not_encrypted} = Entry] =
  202: 	erl_make_certs:pem_to_der(filename:join(Datadir, "req.pem")),
  203:     asn1_encode_decode(Entry).
  204: %%--------------------------------------------------------------------
  205: pkcs7_pem() ->
  206:     [{doc, "PKCS-7 PEM-file decode/encode"}].
  207: pkcs7_pem(Config) when is_list(Config) ->
  208:     Datadir = ?config(data_dir, Config),
  209:     [{'ContentInfo', _, not_encrypted} = Entry0] =
  210: 	erl_make_certs:pem_to_der(filename:join(Datadir, "pkcs7_cert.pem")),
  211:     [{'ContentInfo', _, not_encrypted} = Entry1] =
  212: 	erl_make_certs:pem_to_der(filename:join(Datadir, "pkcs7_ext.pem")),
  213:     asn1_encode_decode(Entry0),
  214:     asn1_encode_decode(Entry1).
  215:       
  216: %%--------------------------------------------------------------------
  217: cert_pem() ->
  218:     [{doc, "Certificate PEM-file decode/encode"}].
  219: cert_pem(Config) when is_list(Config) ->
  220:     Datadir = ?config(data_dir, Config),
  221:    
  222:     [{'Certificate', _, not_encrypted} = Entry0] =  
  223: 	erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")),
  224:     
  225:     asn1_encode_decode(Entry0),
  226:     
  227:     [{'Certificate', _, not_encrypted} = Entry1, 
  228:      {'Certificate', _, not_encrypted} = Entry2] = 
  229:         erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")),
  230:     
  231:     asn1_encode_decode(Entry1),
  232:     asn1_encode_decode(Entry2).
  233: 
  234: %%--------------------------------------------------------------------
  235: ssh_rsa_public_key() ->
  236:     [{doc, "ssh rsa public key decode/encode"}].
  237: ssh_rsa_public_key(Config) when is_list(Config) ->
  238:     Datadir = ?config(data_dir, Config),
  239: 
  240:     {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")),
  241:     [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key),
  242:     [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key),
  243: 
  244:     {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")),
  245:     [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key),
  246:     [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key),
  247: 
  248:     %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh
  249:     %% = RSARawOpenSsh as line breakpoints may differ
  250: 
  251:     EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
  252:     EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
  253: 
  254:     [{PubKey, Attributes1}] =
  255: 	public_key:ssh_decode(EncodedSSh, public_key),
  256:     [{PubKey, Attributes2}] =
  257: 	public_key:ssh_decode(EncodedOpenSsh, public_key).
  258: 
  259: %%--------------------------------------------------------------------
  260: 
  261: ssh_dsa_public_key() ->
  262:     [{doc, "ssh dsa public key decode/encode"}].
  263: ssh_dsa_public_key(Config) when is_list(Config) ->
  264:     Datadir = ?config(data_dir, Config),
  265: 
  266:     {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")),
  267:     [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key),
  268:     [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key),
  269: 
  270:     {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")),
  271:     [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key),
  272:     [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key),
  273: 
  274:     %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh
  275:     %% = DSARawOpenSsh as line breakpoints may differ
  276: 
  277:     EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
  278:     EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
  279: 
  280:     [{PubKey, Attributes1}] =
  281: 	public_key:ssh_decode(EncodedSSh, public_key),
  282:     [{PubKey, Attributes2}] =
  283: 	public_key:ssh_decode(EncodedOpenSsh, public_key).
  284: 
  285: %%--------------------------------------------------------------------
  286: ssh_rfc4716_rsa_comment() ->
  287:     [{doc, "Test comment header and rsa key"}].
  288: ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
  289:     Datadir = ?config(data_dir, Config),
  290: 
  291:     {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")),
  292:     [{#'RSAPublicKey'{} = PubKey, Attributes}] =
  293:         public_key:ssh_decode(RSARawSsh2, public_key),
  294: 
  295:     Headers = proplists:get_value(headers, Attributes),
  296: 
  297:     Value = proplists:get_value("Comment", Headers, undefined),
  298:     true = Value =/= undefined,
  299:     RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key).
  300: 
  301: %%--------------------------------------------------------------------
  302: ssh_rfc4716_dsa_comment() ->
  303:      [{doc, "Test comment header and dsa key"}].
  304: ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
  305:     Datadir = ?config(data_dir, Config),
  306: 
  307:     {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")),
  308:     [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] =
  309:         public_key:ssh_decode(DSARawSsh2, public_key),
  310: 
  311:     Headers = proplists:get_value(headers, Attributes),
  312: 
  313:     Value = proplists:get_value("Comment", Headers, undefined),
  314:     true = Value =/= undefined,
  315: 
  316:     %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ
  317:     Encoded  = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
  318:     [{PubKey, Attributes}] =
  319:         public_key:ssh_decode(Encoded, public_key).
  320: 
  321: %%--------------------------------------------------------------------
  322: ssh_rfc4716_rsa_subject() ->
  323:     [{doc,  "Test another header value than comment"}].
  324: ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
  325:     Datadir = ?config(data_dir, Config),
  326: 
  327:     {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")),
  328:     [{#'RSAPublicKey'{} = PubKey, Attributes}] =
  329:         public_key:ssh_decode(RSARawSsh2, public_key),
  330: 
  331:     Headers = proplists:get_value(headers, Attributes),
  332: 
  333:     Value = proplists:get_value("Subject", Headers, undefined),
  334:     true = Value =/= undefined,
  335: 
  336:     %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ
  337:     Encoded  = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
  338:     [{PubKey, Attributes}] =
  339:         public_key:ssh_decode(Encoded, public_key).
  340: 
  341: %%--------------------------------------------------------------------
  342: ssh_known_hosts() ->
  343:     [{doc, "ssh known hosts file encode/decode"}].
  344: ssh_known_hosts(Config) when is_list(Config) ->
  345:     Datadir = ?config(data_dir, Config),
  346: 
  347:     {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")),
  348:     [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},
  349:      {#'RSAPublicKey'{}, Attributes3}, {#'RSAPublicKey'{}, Attributes4}] = Decoded =
  350:         public_key:ssh_decode(SshKnownHosts, known_hosts),
  351: 
  352:     Comment1 = undefined,
  353:     Comment2 = "foo@bar.com",
  354:     Comment3 = "Comment with whitespaces",
  355:     Comment4 = "foo@bar.com Comment with whitespaces",
  356:     	
  357:     Comment1 = proplists:get_value(comment, Attributes1, undefined),
  358:     Comment2 = proplists:get_value(comment, Attributes2),
  359:     Comment3 = proplists:get_value(comment, Attributes3),
  360:     Comment4 = proplists:get_value(comment, Attributes4),	
  361: 
  362:     Value1 = proplists:get_value(hostnames, Attributes1, undefined),
  363:     Value2 = proplists:get_value(hostnames, Attributes2, undefined),
  364:     true = (Value1 =/= undefined) and (Value2 =/= undefined),
  365: 
  366:     Encoded = public_key:ssh_encode(Decoded, known_hosts),
  367:     Decoded = public_key:ssh_decode(Encoded, known_hosts).
  368: 
  369: %%--------------------------------------------------------------------
  370: 
  371: ssh1_known_hosts() ->
  372:     [{doc, "ssh (ver 1) known hosts file encode/decode"}].
  373: ssh1_known_hosts(Config) when is_list(Config) ->
  374:     Datadir = ?config(data_dir, Config),
  375: 
  376:     {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")),
  377:     [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}] 
  378: 	= Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts),
  379: 
  380:     Value1 = proplists:get_value(hostnames, Attributes1, undefined),
  381:     Value2 = proplists:get_value(hostnames, Attributes2, undefined),
  382:     true = (Value1 =/= undefined) and (Value2 =/= undefined),
  383: 
  384:     Comment ="dhopson@VMUbuntu-DSH comment with whitespaces",
  385:     Comment = proplists:get_value(comment, Attributes3),
  386: 
  387:     Encoded = public_key:ssh_encode(Decoded, known_hosts),
  388:     Decoded = public_key:ssh_decode(Encoded, known_hosts).
  389: 
  390: %%--------------------------------------------------------------------
  391: ssh_auth_keys() ->
  392:     [{doc, "ssh authorized keys file encode/decode"}].
  393: ssh_auth_keys(Config) when is_list(Config) ->
  394:     Datadir = ?config(data_dir, Config),
  395: 
  396:     {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")),
  397:     [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2},
  398:      {#'RSAPublicKey'{}, Attributes3}, {{_, #'Dss-Parms'{}}, Attributes4}
  399:     ] = Decoded =
  400:         public_key:ssh_decode(SshAuthKeys, auth_keys),
  401: 
  402:     Value1 = proplists:get_value(options, Attributes1, undefined),
  403:     true = Value1 =/= undefined,
  404: 
  405:     Comment1 = Comment2 = "dhopson@VMUbuntu-DSH",
  406:     Comment3 = Comment4 ="dhopson@VMUbuntu-DSH comment with whitespaces",
  407:     
  408:     Comment1 = proplists:get_value(comment, Attributes1),
  409:     Comment2 = proplists:get_value(comment, Attributes2),
  410:     Comment3 = proplists:get_value(comment, Attributes3),
  411:     Comment4 = proplists:get_value(comment, Attributes4),
  412: 
  413:     Encoded = public_key:ssh_encode(Decoded, auth_keys),
  414:     Decoded = public_key:ssh_decode(Encoded, auth_keys).
  415: 
  416: %%--------------------------------------------------------------------
  417: ssh1_auth_keys() ->
  418:     [{doc, "ssh (ver 1) authorized keys file encode/decode"}].
  419: ssh1_auth_keys(Config) when is_list(Config) ->
  420:     Datadir = ?config(data_dir, Config),
  421: 
  422:     {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")),
  423:     [{#'RSAPublicKey'{}, Attributes1},
  424:      {#'RSAPublicKey'{}, Attributes2}, {#'RSAPublicKey'{}, Attributes3},
  425:      {#'RSAPublicKey'{}, Attributes4}, {#'RSAPublicKey'{}, Attributes5}] = Decoded =
  426:         public_key:ssh_decode(SshAuthKeys, auth_keys),
  427: 
  428:     Value1 = proplists:get_value(bits, Attributes2, undefined),
  429:     Value2 = proplists:get_value(bits, Attributes3, undefined),
  430:     true = (Value1 =/= undefined) and (Value2 =/= undefined),
  431: 
  432:     Comment2 = Comment3 = "dhopson@VMUbuntu-DSH",
  433:     Comment4 = Comment5 ="dhopson@VMUbuntu-DSH comment with whitespaces",
  434:     
  435:     undefined = proplists:get_value(comment, Attributes1, undefined),
  436:     Comment2 = proplists:get_value(comment, Attributes2),
  437:     Comment3 = proplists:get_value(comment, Attributes3),
  438:     Comment4 = proplists:get_value(comment, Attributes4),
  439:     Comment5 = proplists:get_value(comment, Attributes5),
  440: 
  441:     Encoded = public_key:ssh_encode(Decoded, auth_keys),
  442:     Decoded = public_key:ssh_decode(Encoded, auth_keys).
  443: 
  444: %%--------------------------------------------------------------------
  445: ssh_openssh_public_key_with_comment() ->
  446:     [{doc, "Test that emty lines and lines starting with # are ignored"}].
  447: ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
  448:     Datadir = ?config(data_dir, Config),
  449: 
  450:     {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")),
  451:     [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key).
  452: 
  453: %%--------------------------------------------------------------------
  454: ssh_openssh_public_key_long_header() ->
  455:   [{doc, "Test that long headers are handled"}].
  456: ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
  457:     Datadir = ?config(data_dir, Config),
  458: 
  459:     {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")),
  460:     [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key),
  461: 
  462:     Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key),
  463:     Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
  464: 
  465: %%--------------------------------------------------------------------
  466: encrypt_decrypt() ->
  467:     [{doc, "Test public_key:encrypt_private and public_key:decrypt_public"}].
  468: encrypt_decrypt(Config) when is_list(Config) -> 
  469:     {PrivateKey, _DerKey} = erl_make_certs:gen_rsa(64),
  470:     #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = PrivateKey,
  471:     PublicKey = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
  472:     Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
  473:     RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey),
  474:     Msg = public_key:decrypt_public(RsaEncrypted, PublicKey),
  475:     Msg = public_key:decrypt_public(RsaEncrypted, PrivateKey),
  476:     RsaEncrypted2 = public_key:encrypt_public(Msg, PublicKey),
  477:     RsaEncrypted3 = public_key:encrypt_public(Msg, PrivateKey),
  478:     Msg = public_key:decrypt_private(RsaEncrypted2, PrivateKey),
  479:     Msg = public_key:decrypt_private(RsaEncrypted3, PrivateKey),
  480: 
  481:     ok.
  482:        
  483: %%--------------------------------------------------------------------
  484: rsa_sign_verify() ->
  485:     [{doc, "Checks that we can sign and verify rsa signatures."}].
  486: rsa_sign_verify(Config) when is_list(Config) ->
  487:     Ca = {_, CaKey} = erl_make_certs:make_cert([]),
  488:     {Cert1, _} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
  489:     PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = 
  490: 	public_key:pem_entry_decode(CaKey),
  491:     PublicRSA = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
  492:     true = public_key:pkix_verify(Cert1, PublicRSA),
  493: 
  494:     Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
  495:     RSASign = public_key:sign(Msg, sha, PrivateRSA),
  496:     true = public_key:verify(Msg, sha, RSASign, PublicRSA), 
  497:     false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA), 
  498:     false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), 
  499: 
  500:     RSASign1 = public_key:sign(Msg, md5, PrivateRSA),
  501:     true = public_key:verify(Msg, md5, RSASign1, PublicRSA).
  502:     
  503: %%--------------------------------------------------------------------
  504: 
  505: dsa_sign_verify() ->
  506:     [{doc, "Checks that we can sign and verify dsa signatures."}].
  507: dsa_sign_verify(Config) when is_list(Config) ->
  508:     Ca = erl_make_certs:make_cert([]),
  509:     CertInfo = {_,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]),
  510:     {Cert2,_CertKey} = erl_make_certs:make_cert([{issuer, CertInfo}]),
  511: 
  512:     #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} =
  513: 	public_key:pem_entry_decode(CertKey1),
  514:     true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}),
  515: 
  516:     Datadir = ?config(data_dir, Config),
  517:     [DsaKey = {'DSAPrivateKey', _, _}] = 
  518: 	erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), 
  519:     DSAPrivateKey = public_key:pem_entry_decode(DsaKey),
  520:     #'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey,
  521: 
  522:     Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
  523:     DSASign = public_key:sign(Msg, sha, DSAPrivateKey),
  524:     DSAPublicKey = Y1,
  525:     DSAParams = #'Dss-Parms'{p=P1, q=Q1, g=G1},
  526:     true = public_key:verify(Msg, sha, DSASign, {DSAPublicKey, DSAParams}), 
  527:     false = public_key:verify(<<1:8, Msg/binary>>, sha, DSASign, 
  528: 			      {DSAPublicKey, DSAParams}), 
  529:     false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>, 
  530: 			      {DSAPublicKey, DSAParams}), 
  531:     
  532:     Digest = crypto:hash(sha,Msg),
  533:     DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
  534:     true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}), 
  535:     <<_:8, RestDigest/binary>> = Digest,
  536:     false = public_key:verify(<<1:8, RestDigest/binary>>, none, DigestSign, 
  537: 			      {DSAPublicKey, DSAParams}), 
  538:     false = public_key:verify(Digest, none, <<1:8, DigestSign/binary>>, 
  539: 			      {DSAPublicKey, DSAParams}).
  540: 
  541: %%--------------------------------------------------------------------
  542: pkix() ->
  543:     [{doc, "Misc pkix tests not covered elsewhere"}].
  544: pkix(Config) when is_list(Config) ->
  545:     Datadir = ?config(data_dir, Config),
  546:     Certs0 = erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")),
  547:     Certs1 = erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")),
  548:     TestTransform = fun({'Certificate', CertDer, not_encrypted}) ->
  549: 			    PlainCert = public_key:pkix_decode_cert(CertDer, plain),
  550: 			    OtpCert = public_key:pkix_decode_cert(CertDer, otp),
  551: 			    CertDer = 
  552: 				public_key:pkix_encode('OTPCertificate', OtpCert, otp),
  553: 			    CertDer = 
  554: 				public_key:pkix_encode('Certificate', PlainCert, plain),
  555: 			    OTPTBS = OtpCert#'OTPCertificate'.tbsCertificate,
  556: 			    OTPSubj = OTPTBS#'OTPTBSCertificate'.subject, 
  557: 			    DNEncoded = public_key:pkix_encode('Name', OTPSubj, otp),
  558: 			    PlainTBS = PlainCert#'Certificate'.tbsCertificate,
  559: 			    Subj2 = PlainTBS#'TBSCertificate'.subject,
  560: 			    DNEncoded = public_key:pkix_encode('Name', Subj2, plain),
  561: 
  562: 			    false = public_key:pkix_is_fixed_dh_cert(CertDer)
  563: 		    end,
  564:     [TestTransform(Cert) || Cert <- Certs0 ++ Certs1],
  565: 
  566:     true = public_key:pkix_is_self_signed(element(2,hd(Certs0))),
  567:     false = public_key:pkix_is_self_signed(element(2,hd(Certs1))),
  568: 
  569:     CaIds = [element(2, public_key:pkix_issuer_id(Cert, self)) || 
  570: 		{'Certificate', Cert, _} <- Certs0],
  571:     {ok, IssuerId = {_, _IssuerName}} = 
  572: 	public_key:pkix_issuer_id(element(2,hd(Certs1)), other),
  573: 
  574:     true = lists:member(IssuerId, CaIds),
  575: 
  576:     %% Should be normalized allready
  577:     TestStr   = {rdnSequence, 
  578: 		 [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}],
  579: 		  [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang  ca "}}]]},
  580:     VerifyStr = {rdnSequence, 
  581: 		 [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}],
  582: 		  [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]},
  583:     VerifyStr = public_key:pkix_normalize_name(TestStr),
  584: 
  585:     ok.
  586: 
  587: %%--------------------------------------------------------------------
  588: pkix_countryname() ->
  589:     [{doc, "Test workaround for certs that code x509countryname as utf8"}].
  590: pkix_countryname(Config) when is_list(Config) ->
  591:     Cert = incorrect_countryname_pkix_cert(),
  592:     OTPCert = public_key:pkix_decode_cert(Cert, otp),
  593:     TBSCert = OTPCert#'OTPCertificate'.tbsCertificate,
  594:     Issuer = TBSCert#'OTPTBSCertificate'.issuer,
  595:     Subj   = TBSCert#'OTPTBSCertificate'.subject,
  596:     check_countryname(Issuer),
  597:     check_countryname(Subj).
  598: 
  599: %%--------------------------------------------------------------------
  600: pkix_emailaddress() ->
  601:     [{doc, "Test workaround for certs that code emailAddress as utf8"}].
  602: pkix_emailaddress(Config) when is_list(Config) ->
  603:     Cert = incorrect_emailaddress_pkix_cert(),
  604:     OTPCert = public_key:pkix_decode_cert(Cert, otp),
  605:     TBSCert = OTPCert#'OTPCertificate'.tbsCertificate,
  606:     Issuer = TBSCert#'OTPTBSCertificate'.issuer,
  607:     Subj   = TBSCert#'OTPTBSCertificate'.subject,
  608:     check_emailaddress(Issuer),
  609:     check_emailaddress(Subj).
  610: 
  611: %%--------------------------------------------------------------------
  612: pkix_path_validation() ->
  613:     [{doc, "Test PKIX path validation"}].
  614: pkix_path_validation(Config) when is_list(Config) ->
  615:     CaK = {Trusted,_} = 
  616: 	erl_make_certs:make_cert([{key, dsa},
  617: 			     {subject, [
  618: 					{name, "Public Key"},
  619: 					{?'id-at-name', {printableString, "public_key"}},
  620: 					{?'id-at-pseudonym', {printableString, "pubkey"}},
  621: 					{city, "Stockholm"},
  622: 					{country, "SE"},
  623: 					{org, "erlang"},
  624: 					{org_unit, "testing dep"}
  625: 				       ]}
  626: 			    ]),
  627:     ok = erl_make_certs:write_pem("./", "public_key_cacert", CaK),
  628: 
  629:     CertK1 = {Cert1, _} = erl_make_certs:make_cert([{issuer, CaK}]),
  630:     CertK2 = {Cert2,_} = erl_make_certs:make_cert([{issuer, CertK1}, 
  631: 					      {digest, md5}, {extensions, false}]),
  632:     ok = erl_make_certs:write_pem("./", "public_key_cert", CertK2),
  633:     
  634:     {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1], []),
  635:     
  636:     {error, {bad_cert,invalid_issuer}} = 
  637: 	public_key:pkix_path_validation(Trusted, [Cert2], []),
  638:     
  639:     {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1, Cert2], []),    
  640:     {error, issuer_not_found} = public_key:pkix_issuer_id(Cert2, other),
  641: 
  642:     CertK3 = {Cert3,_}  = erl_make_certs:make_cert([{issuer, CertK1}, 
  643: 					       {extensions, [{basic_constraints, false}]}]),
  644:     {Cert4,_}  = erl_make_certs:make_cert([{issuer, CertK3}, {extensions, [{key_usage, undefined}]}]),
  645: 
  646:     {error, {bad_cert,missing_basic_constraint}} =
  647: 	public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], []),
  648: 
  649:     VerifyFunAndState0  = {fun(_,{bad_cert, missing_basic_constraint}, UserState) ->
  650: 				   {valid, UserState};
  651: 			      (_,{bad_cert, _} = Reason, _) ->
  652: 				   {fail, Reason};
  653: 			      (_,{extension, _}, UserState) ->
  654: 				   {unknown, UserState};
  655: 			      (_, valid, UserState) ->
  656: 				   {valid, UserState};
  657: 			      (_, valid_peer, UserState) ->
  658: 				   {valid, UserState}
  659: 			   end, []},
  660:     {ok, _} =
  661: 	public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4],
  662: 					[{verify_fun, VerifyFunAndState0}]),
  663: 
  664:     {error, {bad_cert, unknown_ca}} =
  665: 	public_key:pkix_path_validation(unknown_ca, [Cert1, Cert3, Cert4], []),
  666: 
  667:     VerifyFunAndState1 =
  668: 	{fun(_,{bad_cert, unknown_ca}, UserState) ->
  669: 		 {valid, UserState};
  670: 	    (_,{bad_cert, _} = Reason, _) ->
  671: 		 {fail, Reason};
  672: 	    (_,{extension, _}, UserState) ->
  673: 		 {unknown, UserState};
  674: 	    (_, valid, UserState) ->
  675: 		 {valid, UserState}
  676: 	 end, []},
  677: 
  678:     {ok, _} =
  679: 	public_key:pkix_path_validation(unknown_ca, [Cert1], [{verify_fun,
  680: 							      VerifyFunAndState1}]),
  681:     ok.
  682: 
  683: %%--------------------------------------------------------------------
  684: pkix_iso_rsa_oid() ->
  685:  [{doc, "Test workaround for supporting certs that use ISO oids"
  686:    " 1.3.14.3.2.29 instead of PKIX/PKCS oid"}].
  687: pkix_iso_rsa_oid(Config) when is_list(Config) ->
  688:     Datadir = ?config(data_dir, Config),
  689:     {ok, PemCert} = file:read_file(filename:join(Datadir, "rsa_ISO.pem")),
  690:     [{_, Cert, _}] = public_key:pem_decode(PemCert),
  691:     OTPCert = public_key:pkix_decode_cert(Cert, otp),
  692:     SigAlg = OTPCert#'OTPCertificate'.signatureAlgorithm,
  693:     {_, rsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm).
  694: 
  695: %%--------------------------------------------------------------------
  696: pkix_iso_dsa_oid() ->
  697:  [{doc, "Test workaround for supporting certs that use ISO oids"
  698:    "1.3.14.3.2.27 instead of PKIX/PKCS oid"}].
  699: pkix_iso_dsa_oid(Config) when is_list(Config) ->
  700:     Datadir = ?config(data_dir, Config),
  701:     {ok, PemCert} = file:read_file(filename:join(Datadir, "dsa_ISO.pem")),
  702:     [{_, Cert, _}] = public_key:pem_decode(PemCert),
  703:     OTPCert = public_key:pkix_decode_cert(Cert, otp),
  704:     SigAlg = OTPCert#'OTPCertificate'.signatureAlgorithm,
  705:     {_, dsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm).
  706: 
  707: %%--------------------------------------------------------------------
  708: %% Internal functions ------------------------------------------------
  709: %%--------------------------------------------------------------------
  710: asn1_encode_decode({Asn1Type, Der, not_encrypted} = Entry) ->
  711:     Decoded = public_key:der_decode(Asn1Type, Der),
  712:     Decoded = public_key:pem_entry_decode(Entry),
  713:     Entry = public_key:pem_entry_encode(Asn1Type, Decoded),
  714:     ok.
  715:     
  716: check_countryname({rdnSequence,DirName}) ->
  717:     do_check_countryname(DirName).
  718: do_check_countryname([]) ->
  719:     ok;
  720: do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
  721: 					       value = "US"}|_]) ->
  722:     ok;
  723: do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
  724: 					       value =  Value}|_]) ->
  725:     ct:fail({incorrect_country_name, Value});
  726: do_check_countryname([_| Rest]) ->
  727:     do_check_countryname(Rest).
  728: 
  729: check_emailaddress({rdnSequence,DirName}) ->
  730:     do_check_emailaddress(DirName).
  731: do_check_emailaddress([]) ->
  732:     ok;
  733: do_check_emailaddress([#'AttributeTypeAndValue'{type = ?'id-emailAddress',
  734: 					       value = "invalid@email.com"}|_]) ->
  735:     ok;
  736: do_check_emailaddress([#'AttributeTypeAndValue'{type = ?'id-emailAddress',
  737: 					       value =  Value}|_]) ->
  738:     ct:fail({incorrect_email_address, Value});
  739: do_check_emailaddress([_| Rest]) ->
  740:     do_check_emailaddress(Rest).
  741: 
  742: check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') ->
  743:     true;
  744: check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') ->
  745:     true;
  746: check_entry_type(#'RSAPublicKey'{}, 'RSAPublicKey') ->
  747:     true;
  748: check_entry_type({_Int, #'Dss-Parms'{}}, 'DSAPublicKey') when is_integer(_Int) ->
  749:     true;
  750: check_entry_type(#'DHParameter'{}, 'DHParameter') ->
  751:     true;
  752: check_entry_type(#'Certificate'{}, 'Certificate') ->
  753:     true;
  754: check_entry_type(_,_) ->
  755:     false.
  756: 
  757: strip_ending_newlines(Bin) ->
  758:     string:strip(binary_to_list(Bin), right, 10).
  759: 
  760: incorrect_countryname_pkix_cert() ->
  761:     <<48,130,5,186,48,130,4,162,160,3,2,1,2,2,7,7,250,61,63,6,140,137,48,13,6,9,42, 134,72,134,247,13,1,1,5,5,0,48,129,220,49,11,48,9,6,3,85,4,6,19,2,85,83,49, 16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19, 10,83,99,111,116,116,115,100,97,108,101,49,37,48,35,6,3,85,4,10,19,28,83,116, 97,114,102,105,101,108,100,32,84,101,99,104,110,111,108,111,103,105,101,115, 44,32,73,110,99,46,49,57,48,55,6,3,85,4,11,19,48,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 49,49,48,47,6,3,85,4,3,19,40,83,116,97,114,102,105,101,108,100,32,83,101,99, 117,114,101,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117, 116,104,111,114,105,116,121,49,17,48,15,6,3,85,4,5,19,8,49,48,54,56,56,52,51, 53,48,30,23,13,49,48,49,48,50,51,48,49,51,50,48,53,90,23,13,49,50,49,48,50, 51,48,49,51,50,48,53,90,48,122,49,11,48,9,6,3,85,4,6,12,2,85,83,49,11,48,9,6, 3,85,4,8,12,2,65,90,49,19,48,17,6,3,85,4,7,12,10,83,99,111,116,116,115,100, 97,108,101,49,38,48,36,6,3,85,4,10,12,29,83,112,101,99,105,97,108,32,68,111, 109,97,105,110,32,83,101,114,118,105,99,101,115,44,32,73,110,99,46,49,33,48, 31,6,3,85,4,3,12,24,42,46,108,111,103,105,110,46,115,101,99,117,114,101,115, 101,114,118,101,114,46,110,101,116,48,130,1,34,48,13,6,9,42,134,72,134,247, 13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,185,136,240,80,141,36,124, 245,182,130,73,19,188,74,166,117,72,228,185,209,43,129,244,40,44,193,231,11, 209,12,234,88,43,142,1,162,48,122,17,95,230,105,171,131,12,147,46,204,36,80, 250,171,33,253,35,62,83,22,71,212,186,141,14,198,89,89,121,204,224,122,246, 127,110,188,229,162,67,95,6,74,231,127,99,131,7,240,85,102,203,251,50,58,58, 104,245,103,181,183,134,32,203,121,232,54,32,188,139,136,112,166,126,14,91, 223,153,172,164,14,61,38,163,208,215,186,210,136,213,143,70,147,173,109,217, 250,169,108,31,211,104,238,103,93,182,59,165,43,196,189,218,241,30,148,240, 109,90,69,176,194,52,116,173,151,135,239,10,209,179,129,192,102,75,11,25,168, 223,32,174,84,223,134,70,167,55,172,143,27,130,123,226,226,7,34,142,166,39, 48,246,96,231,150,84,220,106,133,193,55,95,159,227,24,249,64,36,1,142,171,16, 202,55,126,7,156,15,194,22,116,53,113,174,104,239,203,120,45,131,57,87,84, 163,184,27,83,57,199,91,200,34,43,98,61,180,144,76,65,170,177,2,3,1,0,1,163, 130,1,224,48,130,1,220,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,0,48,29,6,3, 85,29,37,4,22,48,20,6,8,43,6,1,5,5,7,3,1,6,8,43,6,1,5,5,7,3,2,48,14,6,3,85, 29,15,1,1,255,4,4,3,2,5,160,48,56,6,3,85,29,31,4,49,48,47,48,45,160,43,160, 41,134,39,104,116,116,112,58,47,47,99,114,108,46,115,116,97,114,102,105,101, 108,100,116,101,99,104,46,99,111,109,47,115,102,115,50,45,48,46,99,114,108, 48,83,6,3,85,29,32,4,76,48,74,48,72,6,11,96,134,72,1,134,253,110,1,7,23,2,48, 57,48,55,6,8,43,6,1,5,5,7,2,1,22,43,104,116,116,112,115,58,47,47,99,101,114, 116,115,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99,111,109, 47,114,101,112,111,115,105,116,111,114,121,47,48,129,141,6,8,43,6,1,5,5,7,1, 1,4,129,128,48,126,48,42,6,8,43,6,1,5,5,7,48,1,134,30,104,116,116,112,58,47, 47,111,99,115,112,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99, 111,109,47,48,80,6,8,43,6,1,5,5,7,48,2,134,68,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 47,115,102,95,105,110,116,101,114,109,101,100,105,97,116,101,46,99,114,116, 48,31,6,3,85,29,35,4,24,48,22,128,20,73,75,82,39,209,27,188,242,161,33,106, 98,123,81,66,122,138,215,213,86,48,59,6,3,85,29,17,4,52,48,50,130,24,42,46, 108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118,101,114,46,110, 101,116,130,22,108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118, 101,114,46,110,101,116,48,29,6,3,85,29,14,4,22,4,20,138,233,191,208,157,203, 249,85,242,239,20,195,48,10,148,49,144,101,255,116,48,13,6,9,42,134,72,134, 247,13,1,1,5,5,0,3,130,1,1,0,82,31,121,162,49,50,143,26,167,202,143,61,71, 189,201,199,57,81,122,116,90,192,88,24,102,194,174,48,157,74,27,87,210,223, 253,93,3,91,150,109,120,1,110,27,11,200,198,141,222,246,14,200,71,105,41,138, 13,114,122,106,63,17,197,181,234,121,61,89,74,65,41,231,248,219,129,83,176, 219,55,107,55,211,112,98,38,49,69,77,96,221,108,123,152,12,210,159,157,141, 43,226,55,187,129,3,82,49,136,66,81,196,91,234,196,10,82,48,6,80,163,83,71, 127,102,177,93,209,129,26,104,2,84,24,255,248,161,3,244,169,234,92,122,110, 43,4,17,113,185,235,108,219,210,236,132,216,177,227,17,169,58,162,159,182, 162,93,160,229,200,9,163,229,110,121,240,168,232,14,91,214,188,196,109,210, 164,222,0,109,139,132,113,91,16,118,173,178,176,80,132,34,41,199,51,206,250, 224,132,60,115,192,94,107,163,219,212,226,225,65,169,148,108,213,46,174,173, 103,110,189,229,166,149,254,31,51,44,144,108,187,182,11,251,201,206,86,138, 208,59,51,86,132,235,81,225,88,34,190,8,184>>.
  762: 
  763: incorrect_emailaddress_pkix_cert() ->
  764:     <<48,130,3,74,48,130,2,50,2,9,0,133,49,203,25,198,156,252,230,48,13,6,9,42,134, 72,134,247,13,1,1,5,5,0,48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17, 6,3,85,4,8,12,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10, 12,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116, 121,32,76,116,100,49,32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110, 118,97,108,105,100,64,101,109,97,105,108,46,99,111,109,48,30,23,13,49,51,49, 49,48,55,50,48,53,54,49,56,90,23,13,49,52,49,49,48,55,50,48,53,54,49,56,90, 48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,12,10,83,111, 109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,12,24,73,110,116,101, 114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,49, 32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110,118,97,108,105,100,64, 101,109,97,105,108,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13, 1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,190,243,49,213,219,60,232,105, 1,127,126,9,130,15,60,190,78,100,148,235,246,223,21,91,238,200,251,84,55,212, 78,32,120,61,85,172,0,144,248,5,165,29,143,79,64,178,51,153,203,76,115,238, 192,49,173,37,121,203,89,62,157,13,181,166,30,112,154,40,202,140,104,211,157, 73,244,9,78,236,70,153,195,158,233,141,42,238,2,143,160,225,249,27,30,140, 151,176,43,211,87,114,164,108,69,47,39,195,123,185,179,219,28,218,122,53,83, 77,48,81,184,14,91,243,12,62,146,86,210,248,228,171,146,225,87,51,146,155, 116,112,238,212,36,111,58,41,67,27,6,61,61,3,84,150,126,214,121,57,38,12,87, 121,67,244,37,45,145,234,131,115,134,58,194,5,36,166,52,59,229,32,47,152,80, 237,190,58,182,248,98,7,165,198,211,5,31,231,152,116,31,108,71,218,64,188, 178,143,27,167,79,15,112,196,103,116,212,65,197,94,37,4,132,103,91,217,73, 223,207,185,7,153,221,240,232,31,44,102,108,82,83,56,242,210,214,74,71,246, 177,217,148,227,220,230,4,176,226,74,194,37,2,3,1,0,1,48,13,6,9,42,134,72, 134,247,13,1,1,5,5,0,3,130,1,1,0,89,247,141,154,173,123,123,203,143,85,28,79, 73,37,164,6,17,89,171,224,149,22,134,17,198,146,158,192,241,41,253,58,230, 133,71,189,43,66,123,88,15,242,119,227,249,99,137,61,200,54,161,0,177,167, 169,114,80,148,90,22,97,78,162,181,75,93,209,116,245,46,81,232,64,157,93,136, 52,57,229,113,197,218,113,93,42,161,213,104,205,137,30,144,183,58,10,98,47, 227,177,96,40,233,98,150,209,217,68,22,221,133,27,161,152,237,46,36,179,59, 172,97,134,194,205,101,137,71,192,57,153,20,114,27,173,233,166,45,56,0,61, 205,45,202,139,7,132,103,248,193,157,184,123,43,62,172,236,110,49,62,209,78, 249,83,219,133,1,213,143,73,174,16,113,143,189,41,84,60,128,222,30,177,104, 134,220,52,239,171,76,59,176,36,113,176,214,118,16,44,235,21,167,199,216,200, 76,219,142,248,13,70,145,205,216,230,226,148,97,223,216,179,68,209,222,63, 140,137,24,164,192,149,194,79,119,247,75,159,49,116,70,241,70,116,11,40,119, 176,157,36,160,102,140,255,34,248,25,231,136,59>>.