From 006f45a738a6612958381b2fcbf48586c008d911 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 26 Feb 2013 15:52:18 +0100 Subject: public_key & ssl: Add support for ISO oids 1.3.14.3.2.29 and 1.3.14.3.2.27 Some certificates may use these OIDs instead of the ones defined by PKIX/PKCS standard. Refactor code so that all handling of the "duplicate" oids is done by public_key. Update algorithm information in documentation. --- lib/public_key/asn1/OTP-PKIX.asn1 | 22 ++++++++++----- lib/public_key/asn1/PKCS-1.asn1 | 4 ++- lib/public_key/asn1/PKIX1Algorithms88.asn1 | 3 ++ lib/public_key/doc/src/cert_records.xml | 27 ++++++++++++------ lib/public_key/doc/src/public_key.xml | 21 ++++++++++++-- lib/public_key/src/pubkey_cert.erl | 22 ++------------- lib/public_key/src/pubkey_crl.erl | 4 +-- lib/public_key/src/public_key.erl | 32 +++++++++++++++++++++- lib/public_key/test/public_key_SUITE.erl | 30 ++++++++++++++++++-- .../test/public_key_SUITE_data/dsa_ISO.pem | 24 ++++++++++++++++ .../test/public_key_SUITE_data/rsa_ISO.pem | 14 ++++++++++ 11 files changed, 161 insertions(+), 42 deletions(-) create mode 100644 lib/public_key/test/public_key_SUITE_data/dsa_ISO.pem create mode 100644 lib/public_key/test/public_key_SUITE_data/rsa_ISO.pem (limited to 'lib/public_key') diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1 index 4f20208bce..a90fe2840c 100644 --- a/lib/public_key/asn1/OTP-PKIX.asn1 +++ b/lib/public_key/asn1/OTP-PKIX.asn1 @@ -97,9 +97,9 @@ IMPORTS id-pkix1-implicit(19) } --Keys and Signatures - id-dsa, Dss-Parms, DSAPublicKey, - id-dsa-with-sha1, - md2WithRSAEncryption, + id-dsa, Dss-Parms, DSAPublicKey, + id-dsa-with-sha1, id-dsaWithSHA1, + md2WithRSAEncryption, md5WithRSAEncryption, sha1WithRSAEncryption, rsaEncryption, RSAPublicKey, @@ -115,7 +115,6 @@ IMPORTS FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) id-mod-pkix1-algorithms(17) } - md2WithRSAEncryption, md5WithRSAEncryption, sha1WithRSAEncryption, @@ -316,8 +315,8 @@ PublicKeyAlgorithm ::= SEQUENCE { OPTIONAL } SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= { - dsa-with-sha1 | md2-with-rsa-encryption | - md5-with-rsa-encryption | sha1-with-rsa-encryption | + dsa-with-sha1 | dsaWithSHA1 | md2-with-rsa-encryption | + md5-with-rsa-encryption | sha1-with-rsa-encryption | sha-1with-rsa-encryption | sha224-with-rsa-encryption | sha256-with-rsa-encryption | sha384-with-rsa-encryption | @@ -325,7 +324,7 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= { ecdsa-with-sha1 } SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { - dsa | rsa-encryption | dh | kea | ec-public-key } + dsa | rsa-encryption | dh | kea | ec-public-key } -- DSA Keys and Signatures @@ -347,6 +346,11 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { dsa-with-sha1 SIGNATURE-ALGORITHM-CLASS ::= { ID id-dsa-with-sha1 + TYPE DSAParams } + + + dsaWithSHA1 SIGNATURE-ALGORITHM-CLASS ::= { + ID id-dsaWithSHA1 TYPE DSAParams } -- @@ -367,6 +371,10 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= { ID sha1WithRSAEncryption TYPE NULL } + sha-1with-rsa-encryption SIGNATURE-ALGORITHM-CLASS ::= { + ID sha-1WithRSAEncryption + TYPE NULL } + sha224-with-rsa-encryption SIGNATURE-ALGORITHM-CLASS ::= { ID sha224WithRSAEncryption TYPE NULL } diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1 index c83289e779..b5754790e7 100644 --- a/lib/public_key/asn1/PKCS-1.asn1 +++ b/lib/public_key/asn1/PKCS-1.asn1 @@ -35,7 +35,9 @@ sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 } - +-- ISO oid - equvivalent to sha1WithRSAEncryption +sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) sha-1WithRSAEncryption(29)} id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1 index f895b6d0cd..74225747d3 100644 --- a/lib/public_key/asn1/PKIX1Algorithms88.asn1 +++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1 @@ -35,6 +35,9 @@ id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 } + id-dsaWithSHA1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) dsaWithSHA1(27) + } -- encoding for DSA signature generated with SHA-1 hash Dss-Sig-Value ::= SEQUENCE { diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml index ac4b4e4489..c9249d40c3 100644 --- a/lib/public_key/doc/src/cert_records.xml +++ b/lib/public_key/doc/src/cert_records.xml @@ -60,9 +60,6 @@ marker="public_key">public key reference manual or follows here.

-

oid() - a tuple of integers - as generated by the ASN1 compiler.

-

time() = uct_time() | general_time()

uct_time() = {utcTime, "YYMMDDHHMMSSZ"}

@@ -158,6 +155,9 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'

id-dsa-with-sha1 + id-dsaWithSHA1 (ISO alt oid to above) + + md2WithRSAEncryption @@ -165,10 +165,22 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'

sha1WithRSAEncryption + + + sha-1WithRSAEncryption (ISO alt oid to above) + + + sha224WithRSAEncryption - ecdsa-with-SHA1 + sha256WithRSAEncryption + + sha512WithRSAEncryption + + + ecdsa-with-SHA1 + Signature algorithm oids @@ -276,15 +288,14 @@ oid names see table below. Ex: ?'id-dsa-with-sha1'

dhpublicnumber - ecdsa-with-SHA1 - - id-keyExchangeAlgorithm + + id-ecPublicKey + Public key algorithm oids - #'Extension'{ extnID, % id_extensions() | oid() diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 5864de2d57..84300f6e65 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -48,7 +48,7 @@ Supports RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile Supports PKCS-1 - RSA Cryptography Standard - Supports DSA- Digital Signature Algorithm + Supports DSS- Digital Signature Standard (DSA - Digital Signature Algorithm) Supports PKCS-3 - Diffie-Hellman Key Agreement Standard Supports PKCS-5 - Password-Based Cryptography Standard Supports PKCS-8 - Private-Key Information Syntax Standard @@ -72,8 +72,10 @@ -include_lib("public_key/include/public_key.hrl"). -

Data Types

+

Data Types

+

oid() - a tuple of integers as generated by the ASN1 compiler.

+

boolean() = true | false

string() = [bytes()]

@@ -491,6 +493,21 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | + + pkix_sign_types(AlgorithmId) -> {DigestType, SignatureType} + Translates signature algorithm oid to erlang digest and signature algorithm types. + + AlgorithmId = oid() + Signature oid from a certificate or a certificate revocation list + DigestType = rsa_digest_type() | dss_digest_type() + SignatureType = rsa | dsa + + +

Translates signature algorithm oid to erlang digest and signature types. +

+
+
+ pkix_verify(Cert, Key) -> boolean() Verify pkix x.509 certificate signature. diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index f53c94b334..dc8d68c78f 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ validate_time/3, validate_signature/6, validate_issuer/4, validate_names/6, validate_extensions/4, - normalize_general_name/1, digest_type/1, is_self_signed/1, + normalize_general_name/1, is_self_signed/1, is_issuer/2, issuer_id/2, is_fixed_dh_cert/1, verify_data/1, verify_fun/4, select_extension/2, match_name/3, extensions_list/1, cert_auth_key_id/1, time_str_2_gregorian_sec/1]). @@ -426,13 +426,12 @@ extensions_list(asn1_NOVALUE) -> extensions_list(Extensions) -> Extensions. - extract_verify_data(OtpCert, DerCert) -> {_, Signature} = OtpCert#'OTPCertificate'.signature, SigAlgRec = OtpCert#'OTPCertificate'.signatureAlgorithm, SigAlg = SigAlgRec#'SignatureAlgorithm'.algorithm, PlainText = encoded_tbs_cert(DerCert), - DigestType = digest_type(SigAlg), + {DigestType,_} = public_key:pkix_sign_types(SigAlg), {DigestType, PlainText, Signature}. verify_signature(OtpCert, DerCert, Key, KeyParams) -> @@ -451,21 +450,6 @@ encoded_tbs_cert(Cert) -> {'Certificate_tbsCertificate', EncodedTBSCert}, _, _} = PKIXCert, EncodedTBSCert. -digest_type(?sha1WithRSAEncryption) -> - sha; -digest_type(?sha224WithRSAEncryption) -> - sha224; -digest_type(?sha256WithRSAEncryption) -> - sha256; -digest_type(?sha384WithRSAEncryption) -> - sha384; -digest_type(?sha512WithRSAEncryption) -> - sha512; -digest_type(?md5WithRSAEncryption) -> - md5; -digest_type(?'id-dsa-with-sha1') -> - sha. - public_key_info(PublicKeyInfo, #path_validation_state{working_public_key_algorithm = WorkingAlgorithm, diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl index 3e4c3c8b6d..eaba5bfa1b 100644 --- a/lib/public_key/src/pubkey_crl.erl +++ b/lib/public_key/src/pubkey_crl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2012. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -561,7 +561,7 @@ extract_crl_verify_data(CRL, DerCRL) -> #'AlgorithmIdentifier'{algorithm = SigAlg} = CRL#'CertificateList'.signatureAlgorithm, PlainText = encoded_tbs_crl(DerCRL), - DigestType = pubkey_cert:digest_type(SigAlg), + {DigestType, _} = public_key:pkix_sign_types(SigAlg), {DigestType, PlainText, Signature}. encoded_tbs_crl(CRL) -> diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index e753cf3867..736c18cdd4 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -36,6 +36,7 @@ decrypt_public/2, decrypt_public/3, sign/3, verify/4, pkix_sign/2, pkix_verify/2, + pkix_sign_types/1, pkix_is_self_signed/1, pkix_is_fixed_dh_cert/1, pkix_is_issuer/2, @@ -53,6 +54,7 @@ -type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility -type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise. +-type oid() :: tuple(). -define(UINT32(X), X:32/unsigned-big-integer). -define(DER_NULL, <<5, 0>>). @@ -334,6 +336,34 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, privateExponent = D}) -> [crypto:mpint(K) || K <- [E, N, D]]. +%%-------------------------------------------------------------------- + +-spec pkix_sign_types(SignatureAlg::oid()) -> + %% Relevant dsa digest type is subpart of rsa digest type + { DigestType :: rsa_digest_type(), + SignatureType :: rsa | dsa + }. +%% Description: +%%-------------------------------------------------------------------- +pkix_sign_types(?sha1WithRSAEncryption) -> + {sha, rsa}; +pkix_sign_types(?'sha-1WithRSAEncryption') -> + {sha, rsa}; +pkix_sign_types(?sha224WithRSAEncryption) -> + {sha224, rsa}; +pkix_sign_types(?sha256WithRSAEncryption) -> + {sha256, rsa}; +pkix_sign_types(?sha384WithRSAEncryption) -> + {sha384, rsa}; +pkix_sign_types(?sha512WithRSAEncryption) -> + {sha512, rsa}; +pkix_sign_types(?md5WithRSAEncryption) -> + {md5, rsa}; +pkix_sign_types(?'id-dsa-with-sha1') -> + {sha, dsa}; +pkix_sign_types(?'id-dsaWithSHA1') -> + {sha, dsa}. + %%-------------------------------------------------------------------- -spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(), rsa_private_key() | @@ -406,7 +436,7 @@ pkix_sign(#'OTPTBSCertificate'{signature = = SigAlg} = TBSCert, Key) -> Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp), - DigestType = pubkey_cert:digest_type(Alg), + {DigestType, _} = pkix_sign_types(Alg), Signature = sign(Msg, DigestType, Key), Cert = #'OTPCertificate'{tbsCertificate= TBSCert, signatureAlgorithm = SigAlg, diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index ea48479f0b..0de80edeac 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-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,7 +41,8 @@ all() -> {group, ssh_public_key_decode_encode}, encrypt_decrypt, {group, sign_verify}, - pkix, pkix_countryname, pkix_path_validation]. + pkix, pkix_countryname, pkix_path_validation, + pkix_iso_rsa_oid, pkix_iso_dsa_oid]. groups() -> [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem, @@ -688,6 +689,31 @@ pkix_path_validation(Config) when is_list(Config) -> public_key:pkix_path_validation(unknown_ca, [Cert1], [{verify_fun, VerifyFunAndState1}]), ok. + +%%-------------------------------------------------------------------- +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), + {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), + SigAlg = OTPCert#'OTPCertificate'.signatureAlgorithm, + {_, rsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm). + +%%-------------------------------------------------------------------- +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), + {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), + SigAlg = OTPCert#'OTPCertificate'.signatureAlgorithm, + {_, dsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- diff --git a/lib/public_key/test/public_key_SUITE_data/dsa_ISO.pem b/lib/public_key/test/public_key_SUITE_data/dsa_ISO.pem new file mode 100644 index 0000000000..d3541367f0 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/dsa_ISO.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEjCCAqygAwIBAgIQZIIqq4RXfpBKJXV69Jc4BjCCASwGByqGSM44BAMwggEf +AoGBALez5tklY5CdFeTMos899pA6i4u4uCtszgBzrdBk6cl5FVqzdzWMGTQiynnT +pGsrOESinzP06Ip+pG15We2OORwgvCxD/W95aCiN0/+MdiXqlsmboBARMzsa+SmB +ENN3gF/+tuuEAFzOXU1q2cmEywRLyfbM2KIBVE/TChWYw2eRAhUA1R64VvcQ90XA +8SOKVDmMA0dBzukCgYEAlLMYP0pbgBlgHQVO3/avAHlWNrIq52Lxk7SdPJWgMvPj +TK9Z6sv88kxsCcydtjvO439j1yqcwk50GQc+86ktBWWz93/HkIdnFyqafef4mmWv +m2Uq6ClQKS+A0Asfaj8Mys+HUMiI+qsfdjRbyIpwb7MX1nsVdsKzALnZNMW27A0w +HTEbMBkGA1UEAxMSSVNBIFRlc3QgQXV0aG9yaXR5MB4XDTEyMDMyMDE3MTMyMVoX +DTM5MTIzMTIzNTk1OVowHTEbMBkGA1UEAxMSSVNBIFRlc3QgQXV0aG9yaXR5MIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqe3oVLIVBVIPI/uZjrciELODKxPEE +SDWoNvycEeP1ERF5kDlRDmLIQ51Nt0vI5pKTasnIDbB1ONiQ2cvMrj2dkWWl/z2v +f9tqQAzBm/r1LcUmL1bbP2bgk+//n5AJicU1FKecfDeZo0SXChDKSfH3ojdbsS5U +68q0qGHgNoPRawIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ME4GA1UdAQRHMEWA +EEIfCfbwCZs35y8mXWInVuyhHzAdMRswGQYDVQQDExJJU0EgVGVzdCBBdXRob3Jp +dHmCEGSCKquEV36QSiV1evSXOAYwggEsBgcqhkjOOAQDMIIBHwKBgQC3s+bZJWOQ +nRXkzKLPPfaQOouLuLgrbM4Ac63QZOnJeRVas3c1jBk0Isp506RrKzhEop8z9OiK +fqRteVntjjkcILwsQ/1veWgojdP/jHYl6pbJm6AQETM7GvkpgRDTd4Bf/rbrhABc +zl1NatnJhMsES8n2zNiiAVRP0woVmMNnkQIVANUeuFb3EPdFwPEjilQ5jANHQc7p +AoGBAJSzGD9KW4AZYB0FTt/2rwB5VjayKudi8ZO0nTyVoDLz40yvWerL/PJMbAnM +nbY7zuN/Y9cqnMJOdBkHPvOpLQVls/d/x5CHZxcqmn3n+Jplr5tlKugpUCkvgNAL +H2o/DMrPh1DIiPqrH3Y0W8iKcG+zF9Z7FXbCswC52TTFtuwNAzAAMC0CFH/KmkwI +wnL9ecefLjQZ9Au52Kt5AhUAqJ5UEy2hIjCkdBoyuwOVPp5qnUw= +-----END CERTIFICATE----- diff --git a/lib/public_key/test/public_key_SUITE_data/rsa_ISO.pem b/lib/public_key/test/public_key_SUITE_data/rsa_ISO.pem new file mode 100644 index 0000000000..f82efdefc5 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/rsa_ISO.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICGjCCAYegAwIBAgIQZIIqq4RXfpBKJXV69Jc4BjAJBgUrDgMCHQUAMB0xGzAZ +BgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTAeFw0xMjAzMjAxNzEzMjFaFw0zOTEy +MzEyMzU5NTlaMB0xGzAZBgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEAqnt6FSyFQVSDyP7mY63IhCzgysTxBEg1qDb8 +nBHj9REReZA5UQ5iyEOdTbdLyOaSk2rJyA2wdTjYkNnLzK49nZFlpf89r3/bakAM +wZv69S3FJi9W2z9m4JPv/5+QCYnFNRSnnHw3maNElwoQyknx96I3W7EuVOvKtKhh +4DaD0WsCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zBOBgNVHQEERzBFgBBCHwn2 +8AmbN+cvJl1iJ1bsoR8wHTEbMBkGA1UEAxMSSVNBIFRlc3QgQXV0aG9yaXR5ghBk +giqrhFd+kEoldXr0lzgGMAkGBSsOAwIdBQADgYEAIlVecua5Cr1z/cdwQ8znlgOU +U+y/uzg0nupKkopzVnRYhwV4hxZt3izAz4C/SJZB7eL0bUKlg1ceGjbQsGEm0fzF +LEV3vym4G51bxv03Iecwo96G4NgjJ7+9/7ciBVzfxZyfuCpYG1M2LyrbOyuevtTy +2+vIueT0lv6UftgBfIE= +-----END CERTIFICATE----- -- cgit v1.2.3