diff options
Diffstat (limited to 'lib/public_key/test/public_key_SUITE.erl')
-rw-r--r-- | lib/public_key/test/public_key_SUITE.erl | 170 |
1 files changed, 127 insertions, 43 deletions
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index ea5e036a7e..b22b69a0f2 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2015. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,7 +34,8 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + []. all() -> [app, appup, @@ -43,10 +44,11 @@ all() -> encrypt_decrypt, {group, sign_verify}, pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation, - pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl]. + pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name, + short_cert_issuer_hash, short_crl_issuer_hash]. groups() -> - [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem, + [{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem, dh_pem, cert_pem, pkcs7_pem, pkcs10_pem]}, {ssh_public_key_decode_encode, [], [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key, @@ -108,7 +110,7 @@ appup(Config) when is_list(Config) -> dsa_pem() -> [{doc, "DSA PEM-file decode/encode"}]. dsa_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] = erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), @@ -123,15 +125,15 @@ dsa_pem(Config) when is_list(Config) -> DSAPubKey = public_key:pem_entry_decode(PubEntry0), true = check_entry_type(DSAPubKey, 'DSAPublicKey'), PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', DSAPubKey), - DSAPubPemNoEndNewLines = strip_ending_newlines(DSAPubPem), - DSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])). + DSAPubPemNoEndNewLines = strip_superfluous_newlines(DSAPubPem), + DSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])). %%-------------------------------------------------------------------- rsa_pem() -> [{doc, "RSA PEM-file decode/encode"}]. rsa_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry0 ] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")), @@ -151,29 +153,55 @@ rsa_pem(Config) when is_list(Config) -> RSAPubKey = public_key:pem_entry_decode(PubEntry0), true = check_entry_type(RSAPubKey, 'RSAPublicKey'), PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey), - RSAPubPemNoEndNewLines = strip_ending_newlines(RSAPubPem), - RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])), + RSAPubPemNoEndNewLines = strip_superfluous_newlines(RSAPubPem), + RSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])), {ok, RSARawPem} = file:read_file(filename:join(Datadir, "rsa_pub_key.pem")), [{'RSAPublicKey', _, _} = PubEntry1] = public_key:pem_decode(RSARawPem), RSAPubKey = public_key:pem_entry_decode(PubEntry1), - RSARawPemNoEndNewLines = strip_ending_newlines(RSARawPem), - RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])). + RSARawPemNoEndNewLines = strip_superfluous_newlines(RSARawPem), + RSARawPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry1])). + +%%-------------------------------------------------------------------- +ec_pem() -> + [{doc, "EC key PEM-file decode/encode"}]. +ec_pem(Config) when is_list(Config) -> + Datadir = proplists:get_value(data_dir, Config), + {ok, ECPubPem} = file:read_file(filename:join(Datadir, "ec_pubkey.pem")), + [{'SubjectPublicKeyInfo', _, _} = PubEntry0] = + public_key:pem_decode(ECPubPem), + ECPubKey = public_key:pem_entry_decode(PubEntry0), + true = check_entry_type(ECPubKey, 'ECPoint'), + PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', ECPubKey), + ECPubPemNoEndNewLines = strip_superfluous_newlines(ECPubPem), + ECPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])), + + {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "ec_key.pem")), + [{'EcpkParameters', _, not_encrypted} = Entry1, + {'ECPrivateKey', _, not_encrypted} = Entry2] = public_key:pem_decode(ECPrivPem), + + ECParams = public_key:pem_entry_decode(Entry1), + true = check_entry_type(ECParams, 'EcpkParameters'), + ECPrivKey = public_key:pem_entry_decode(Entry2), + true = check_entry_type(ECPrivKey, 'ECPrivateKey'), + ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem), + ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])). + %%-------------------------------------------------------------------- encrypted_pem() -> [{doc, "Encrypted PEM-file decode/encode"}]. encrypted_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'RSAPrivateKey', DerRSAKey, not_encrypted}] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")), RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey), - Salt0 = crypto:rand_bytes(8), + Salt0 = crypto:strong_rand_bytes(8), Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, {{"DES-EDE3-CBC", Salt0}, "1234abcd"}), RSAKey = public_key:pem_entry_decode(Entry0,"1234abcd"), @@ -182,7 +210,7 @@ encrypted_pem(Config) when is_list(Config) -> [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = erl_make_certs:pem_to_der(Des3KeyFile), - Salt1 = crypto:rand_bytes(8), + Salt1 = crypto:strong_rand_bytes(8), Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, {{"DES-CBC", Salt1}, "4567efgh"}), DesKeyFile = filename:join(Datadir, "des_client_key.pem"), @@ -199,7 +227,7 @@ encrypted_pem(Config) when is_list(Config) -> dh_pem() -> [{doc, "DH parametrs PEM-file decode/encode"}]. dh_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'DHParameter', _DerDH, not_encrypted} = Entry] = erl_make_certs:pem_to_der(filename:join(Datadir, "dh.pem")), asn1_encode_decode(Entry). @@ -209,7 +237,7 @@ dh_pem(Config) when is_list(Config) -> pkcs10_pem() -> [{doc, "PKCS-10 PEM-file decode/encode"}]. pkcs10_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'CertificationRequest', _DerPKCS10, not_encrypted} = Entry] = erl_make_certs:pem_to_der(filename:join(Datadir, "req.pem")), asn1_encode_decode(Entry). @@ -217,7 +245,7 @@ pkcs10_pem(Config) when is_list(Config) -> pkcs7_pem() -> [{doc, "PKCS-7 PEM-file decode/encode"}]. pkcs7_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'ContentInfo', _, not_encrypted} = Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "pkcs7_cert.pem")), [{'ContentInfo', _, not_encrypted} = Entry1] = @@ -229,7 +257,7 @@ pkcs7_pem(Config) when is_list(Config) -> cert_pem() -> [{doc, "Certificate PEM-file decode/encode"}]. cert_pem(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [{'Certificate', _, not_encrypted} = Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")), @@ -247,7 +275,7 @@ cert_pem(Config) when is_list(Config) -> ssh_rsa_public_key() -> [{doc, "ssh rsa public key decode/encode"}]. ssh_rsa_public_key(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")), [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key), @@ -273,7 +301,7 @@ ssh_rsa_public_key(Config) when is_list(Config) -> ssh_dsa_public_key() -> [{doc, "ssh dsa public key decode/encode"}]. ssh_dsa_public_key(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")), [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key), @@ -299,7 +327,7 @@ ssh_dsa_public_key(Config) when is_list(Config) -> ssh_ecdsa_public_key() -> [{doc, "ssh ecdsa public key decode/encode"}]. ssh_ecdsa_public_key(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, ECDSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_ecdsa_pub")), [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, public_key), @@ -324,7 +352,7 @@ ssh_ecdsa_public_key(Config) when is_list(Config) -> ssh_rfc4716_rsa_comment() -> [{doc, "Test comment header and rsa key"}]. ssh_rfc4716_rsa_comment(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")), [{#'RSAPublicKey'{} = PubKey, Attributes}] = @@ -340,7 +368,7 @@ ssh_rfc4716_rsa_comment(Config) when is_list(Config) -> ssh_rfc4716_dsa_comment() -> [{doc, "Test comment header and dsa key"}]. ssh_rfc4716_dsa_comment(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")), [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] = @@ -360,7 +388,7 @@ ssh_rfc4716_dsa_comment(Config) when is_list(Config) -> ssh_rfc4716_rsa_subject() -> [{doc, "Test another header value than comment"}]. ssh_rfc4716_rsa_subject(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")), [{#'RSAPublicKey'{} = PubKey, Attributes}] = @@ -380,7 +408,7 @@ ssh_rfc4716_rsa_subject(Config) when is_list(Config) -> ssh_known_hosts() -> [{doc, "ssh known hosts file encode/decode"}]. ssh_known_hosts(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")), [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}, @@ -409,7 +437,7 @@ ssh_known_hosts(Config) when is_list(Config) -> ssh1_known_hosts() -> [{doc, "ssh (ver 1) known hosts file encode/decode"}]. ssh1_known_hosts(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")), [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}] @@ -429,7 +457,7 @@ ssh1_known_hosts(Config) when is_list(Config) -> ssh_auth_keys() -> [{doc, "ssh authorized keys file encode/decode"}]. ssh_auth_keys(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")), [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2}, @@ -455,7 +483,7 @@ ssh_auth_keys(Config) when is_list(Config) -> ssh1_auth_keys() -> [{doc, "ssh (ver 1) authorized keys file encode/decode"}]. ssh1_auth_keys(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")), [{#'RSAPublicKey'{}, Attributes1}, @@ -483,7 +511,7 @@ ssh1_auth_keys(Config) when is_list(Config) -> ssh_openssh_public_key_with_comment() -> [{doc, "Test that emty lines and lines starting with # are ignored"}]. ssh_openssh_public_key_with_comment(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")), [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key). @@ -492,7 +520,7 @@ ssh_openssh_public_key_with_comment(Config) when is_list(Config) -> ssh_openssh_public_key_long_header() -> [{doc, "Test that long headers are handled"}]. ssh_openssh_public_key_long_header(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")), [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key), @@ -551,7 +579,7 @@ dsa_sign_verify(Config) when is_list(Config) -> public_key:pem_entry_decode(CertKey1), true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}), - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), [DsaKey = {'DSAPrivateKey', _, _}] = erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), DSAPrivateKey = public_key:pem_entry_decode(DsaKey), @@ -580,7 +608,7 @@ dsa_sign_verify(Config) when is_list(Config) -> pkix() -> [{doc, "Misc pkix tests not covered elsewhere"}]. pkix(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), Certs0 = erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")), Certs1 = erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")), TestTransform = fun({'Certificate', CertDer, not_encrypted}) -> @@ -617,11 +645,10 @@ pkix(Config) when is_list(Config) -> [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]}, VerifyStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}], - [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]}, - VerifyStr = public_key:pkix_normalize_name(TestStr), - - ok. - + [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}]]}, + VerifyStr = public_key:pkix_normalize_name(TestStr). + + %%-------------------------------------------------------------------- pkix_countryname() -> [{doc, "Test workaround for certs that code x509countryname as utf8"}]. @@ -723,7 +750,7 @@ pkix_iso_rsa_oid() -> [{doc, "Test workaround for supporting certs that use ISO oids" " 1.3.14.3.2.29 instead of PKIX/PKCS oid"}]. pkix_iso_rsa_oid(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, PemCert} = file:read_file(filename:join(Datadir, "rsa_ISO.pem")), [{_, Cert, _}] = public_key:pem_decode(PemCert), OTPCert = public_key:pkix_decode_cert(Cert, otp), @@ -735,7 +762,7 @@ pkix_iso_dsa_oid() -> [{doc, "Test workaround for supporting certs that use ISO oids" "1.3.14.3.2.27 instead of PKIX/PKCS oid"}]. pkix_iso_dsa_oid(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, PemCert} = file:read_file(filename:join(Datadir, "dsa_ISO.pem")), [{_, Cert, _}] = public_key:pem_decode(PemCert), OTPCert = public_key:pkix_decode_cert(Cert, otp), @@ -748,7 +775,7 @@ pkix_crl() -> [{doc, "test pkix_crl_* functions"}]. pkix_crl(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), + Datadir = proplists:get_value(data_dir, Config), {ok, PemCRL} = file:read_file(filename:join(Datadir, "idp_crl.pem")), [{_, CRL, _}] = public_key:pem_decode(PemCRL), @@ -778,6 +805,54 @@ pkix_crl(Config) when is_list(Config) -> reasons = asn1_NOVALUE, distributionPoint = Point} = public_key:pkix_dist_point(OTPIDPCert). +general_name() -> + [{doc, "Test that decoding of general name filed may have other values" + " than {rdnSequence, Seq}"}]. + +general_name(Config) when is_list(Config) -> + DummyRfc822Name = "CN=CNDummy, OU=OUDummy, O=ODummy, C=SE", + {ok, {1, DummyRfc822Name}} = + pubkey_cert:cert_auth_key_id( + #'AuthorityKeyIdentifier'{authorityCertIssuer = + [{rfc822Name, DummyRfc822Name}], + authorityCertSerialNumber = + 1}). +%%-------------------------------------------------------------------- +short_cert_issuer_hash() -> + [{doc, "Test OpenSSL-style hash for certificate issuer"}]. + +short_cert_issuer_hash(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + [{'Certificate', CertDER, _}] = + erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")), + + %% This hash value was obtained by running: + %% openssl x509 -in client_cert.pem -issuer_hash -noout + CertIssuerHash = "d4c8d7e5", + + #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{issuer = Issuer}} = + public_key:pkix_decode_cert(CertDER, otp), + + CertIssuerHash = public_key:short_name_hash(Issuer). + +%%-------------------------------------------------------------------- +short_crl_issuer_hash() -> + [{doc, "Test OpenSSL-style hash for CRL issuer"}]. + +short_crl_issuer_hash(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + [{'CertificateList', CrlDER, _}] = + erl_make_certs:pem_to_der(filename:join(Datadir, "idp_crl.pem")), + + %% This hash value was obtained by running: + %% openssl crl -in idp_crl.pem -hash -noout + CrlIssuerHash = "d6134ed3", + + Issuer = public_key:pkix_crl_issuer(CrlDER), + + CrlIssuerHash = public_key:short_name_hash(Issuer). + + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -825,6 +900,14 @@ check_entry_type(#'DHParameter'{}, 'DHParameter') -> true; check_entry_type(#'Certificate'{}, 'Certificate') -> true; +check_entry_type({#'ECPoint'{}, _}, 'ECPoint') -> + true; +check_entry_type(#'ECPrivateKey'{}, 'ECPrivateKey') -> + true; +check_entry_type({namedCurve, _}, 'EcpkParameters') -> + true; +check_entry_type(#'ECParameters'{}, 'EcpkParameters') -> + true; check_entry_type(_,_) -> false. @@ -837,8 +920,9 @@ check_encapsulated_header([ _ | Rest]) -> check_encapsulated_header([]) -> false. -strip_ending_newlines(Bin) -> - string:strip(binary_to_list(Bin), right, 10). +strip_superfluous_newlines(Bin) -> + Str = string:strip(binary_to_list(Bin), right, 10), + re:replace(Str,"\n\n","\n", [{return,list}, global]). incorrect_countryname_pkix_cert() -> <<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>>. |