Tighten up supported PSS combinations in X.509.

Matching Chromium, Go, and TLS 1.3, only allow SHA-256, SHA-384, and
SHA-512 RSA-PSS signatures, where MGF-1 and message hash match and salt
length is hash length. Sadly, we are stuck tolerating an explicit
trailerField for now. See the certificates in cl/362617931.

This also fixes an overflow bug in handling the salt length. On
platforms with 64-bit long and 32-bit int, we would misinterpret, e.g,
2^62 + 32 as 32. Also clean up the error-handling of maskHash. It was
previously handled in a very confusing way; syntax errors in maskHash
would succeed and only be noticed later, in rsa_mgf1_decode.

I haven't done it in this change, but as a followup, we can, like
Chromium, reduce X.509 signature algorithms down to a single enum.

Update-Note: Unusual RSA-PSS combinations in X.509 are no longer
accepted. This same change (actually a slightly stricter version) has
already landed in Chrome.

Bug: 489
Change-Id: I85ca3a4e14f76358cac13e66163887f6dade1ace
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53865
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
chromium-5359
David Benjamin 2 years ago committed by Boringssl LUCI CQ
parent d45d8933e6
commit a6d321b11f
  1. 161
      crypto/x509/rsa_pss.c
  2. 17
      crypto/x509/test/pss_sha1.pem
  3. 19
      crypto/x509/test/pss_sha1_explicit.pem
  4. 17
      crypto/x509/test/pss_sha1_mgf1_syntax_error.pem
  5. 19
      crypto/x509/test/pss_sha224.pem
  6. 19
      crypto/x509/test/pss_sha256.pem
  7. 19
      crypto/x509/test/pss_sha256_explicit_trailer.pem
  8. 19
      crypto/x509/test/pss_sha256_mgf1_sha384.pem
  9. 18
      crypto/x509/test/pss_sha256_mgf1_syntax_error.pem
  10. 19
      crypto/x509/test/pss_sha256_omit_nulls.pem
  11. 19
      crypto/x509/test/pss_sha256_salt31.pem
  12. 19
      crypto/x509/test/pss_sha256_salt_overflow.pem
  13. 19
      crypto/x509/test/pss_sha256_unknown_mgf.pem
  14. 22
      crypto/x509/test/pss_sha256_wrong_trailer.pem
  15. 19
      crypto/x509/test/pss_sha384.pem
  16. 19
      crypto/x509/test/pss_sha512.pem
  17. 102
      crypto/x509/x509_test.cc
  18. 15
      sources.cmake

@ -56,6 +56,7 @@
#include <openssl/x509.h>
#include <assert.h>
#include <limits.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
@ -87,9 +88,9 @@ IMPLEMENT_ASN1_FUNCTIONS_const(RSA_PSS_PARAMS)
// Given an MGF1 Algorithm ID decode to an Algorithm Identifier
static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
if (alg == NULL || alg->parameter == NULL ||
OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
static X509_ALGOR *rsa_mgf1_decode(const X509_ALGOR *alg) {
if (OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
alg->parameter == NULL ||
alg->parameter->type != V_ASN1_SEQUENCE) {
return NULL;
}
@ -99,30 +100,27 @@ static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
return d2i_X509_ALGOR(NULL, &p, plen);
}
static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
X509_ALGOR **pmaskHash) {
*pmaskHash = NULL;
static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg) {
if (alg->parameter == NULL || alg->parameter->type != V_ASN1_SEQUENCE) {
return NULL;
}
const uint8_t *p = alg->parameter->value.sequence->data;
int plen = alg->parameter->value.sequence->length;
RSA_PSS_PARAMS *pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
if (pss == NULL) {
return NULL;
}
return d2i_RSA_PSS_PARAMS(NULL, &p, plen);
}
*pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
return pss;
static int is_allowed_pss_md(const EVP_MD *md) {
int md_type = EVP_MD_type(md);
return md_type == NID_sha256 || md_type == NID_sha384 ||
md_type == NID_sha512;
}
// allocate and set algorithm ID from EVP_MD, default SHA1
// rsa_md_to_algor sets |*palg| to an |X509_ALGOR| describing the digest |md|,
// which must be an allowed PSS digest.
static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
if (EVP_MD_type(md) == NID_sha1) {
return 1;
}
// SHA-1 should be omitted (DEFAULT), but we do not allow SHA-1.
assert(is_allowed_pss_md(md));
*palg = X509_ALGOR_new();
if (*palg == NULL) {
return 0;
@ -131,15 +129,13 @@ static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
return 1;
}
// Allocate and set MGF1 algorithm ID from EVP_MD
// rsa_md_to_mgf1 sets |*palg| to an |X509_ALGOR| describing MGF-1 with the
// digest |mgf1md|, which must be an allowed PSS digest.
static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) {
// SHA-1 should be omitted (DEFAULT), but we do not allow SHA-1.
assert(is_allowed_pss_md(mgf1md));
X509_ALGOR *algtmp = NULL;
ASN1_STRING *stmp = NULL;
*palg = NULL;
if (EVP_MD_type(mgf1md) == NID_sha1) {
return 1;
}
// need to embed algorithm ID inside another
if (!rsa_md_to_algor(&algtmp, mgf1md) ||
!ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) {
@ -162,37 +158,35 @@ err:
return 0;
}
// convert algorithm ID to EVP_MD, default SHA1
static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
const EVP_MD *md;
static const EVP_MD *rsa_algor_to_md(const X509_ALGOR *alg) {
if (!alg) {
return EVP_sha1();
// If omitted, PSS defaults to SHA-1, which we do not allow.
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return NULL;
}
md = EVP_get_digestbyobj(alg->algorithm);
if (md == NULL) {
const EVP_MD *md = EVP_get_digestbyobj(alg->algorithm);
if (md == NULL || !is_allowed_pss_md(md)) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return NULL;
}
return md;
}
// convert MGF1 algorithm ID to EVP_MD, default SHA1
static const EVP_MD *rsa_mgf1_to_md(const X509_ALGOR *alg,
X509_ALGOR *maskHash) {
const EVP_MD *md;
static const EVP_MD *rsa_mgf1_to_md(const X509_ALGOR *alg) {
if (!alg) {
return EVP_sha1();
}
// Check mask and lookup mask hash algorithm
if (OBJ_obj2nid(alg->algorithm) != NID_mgf1 || maskHash == NULL) {
// If omitted, PSS defaults to MGF-1 with SHA-1, which we do not allow.
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return NULL;
}
md = EVP_get_digestbyobj(maskHash->algorithm);
if (md == NULL) {
// Check mask and lookup mask hash algorithm.
X509_ALGOR *maskHash = rsa_mgf1_decode(alg);
if (maskHash == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return NULL;
}
return md;
const EVP_MD *ret = rsa_algor_to_md(maskHash);
X509_ALGOR_free(maskHash);
return ret;
}
int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
@ -204,18 +198,14 @@ int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
return 0;
}
EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
if (sigmd != mgf1md || !is_allowed_pss_md(sigmd)) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return 0;
}
int md_len = EVP_MD_size(sigmd);
if (saltlen == -1) {
saltlen = EVP_MD_size(sigmd);
} else if (saltlen == -2) {
// TODO(davidben): Forbid this mode. The world has largely standardized on
// salt length matching hash length.
saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) {
saltlen--;
}
} else if (saltlen != (int)EVP_MD_size(sigmd)) {
// We only allow salt length matching hash length and, for now, the -2 case.
saltlen = md_len;
} else if (saltlen != md_len) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
return 0;
}
@ -227,11 +217,12 @@ int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
goto err;
}
if (saltlen != 20) {
pss->saltLength = ASN1_INTEGER_new();
if (!pss->saltLength || !ASN1_INTEGER_set(pss->saltLength, saltlen)) {
goto err;
}
// The DEFAULT value is 20, but this does not match any supported digest.
assert(saltlen != 20);
pss->saltLength = ASN1_INTEGER_new();
if (!pss->saltLength || //
!ASN1_INTEGER_set(pss->saltLength, saltlen)) {
goto err;
}
if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) ||
@ -260,33 +251,38 @@ int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
// Decode PSS parameters
int ret = 0;
X509_ALGOR *maskHash;
RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash);
RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg);
if (pss == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
goto err;
}
const EVP_MD *mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
const EVP_MD *mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm);
const EVP_MD *md = rsa_algor_to_md(pss->hashAlgorithm);
if (mgf1md == NULL || md == NULL) {
goto err;
}
int saltlen = 20;
if (pss->saltLength != NULL) {
saltlen = ASN1_INTEGER_get(pss->saltLength);
// We require the MGF-1 and signing hashes to match.
if (mgf1md != md) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
goto err;
}
// Could perform more salt length sanity checks but the main
// RSA routines will trap other invalid values anyway.
if (saltlen < 0) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
goto err;
}
// We require the salt length be the hash length. The DEFAULT value is 20, but
// this does not match any supported salt length.
uint64_t salt_len = 0;
if (pss->saltLength == NULL ||
!ASN1_INTEGER_get_uint64(&salt_len, pss->saltLength) ||
salt_len != EVP_MD_size(md)) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
goto err;
}
assert(salt_len <= INT_MAX);
// low-level routines support only trailer field 0xbc (value 1)
// and PKCS#1 says we should reject any other value anyway.
// The trailer field must be 1 (0xbc). This value is DEFAULT, so the structure
// is required to omit it in DER. Although a syntax error, we also tolerate an
// explicitly-encoded value. See the certificates in cl/362617931.
if (pss->trailerField != NULL && ASN1_INTEGER_get(pss->trailerField) != 1) {
OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
goto err;
@ -295,7 +291,7 @@ int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
EVP_PKEY_CTX *pctx;
if (!EVP_DigestVerifyInit(ctx, &pctx, md, NULL, pkey) ||
!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
!EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, saltlen) ||
!EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, (int)salt_len) ||
!EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md)) {
goto err;
}
@ -304,7 +300,6 @@ int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
err:
RSA_PSS_PARAMS_free(pss);
X509_ALGOR_free(maskHash);
return ret;
}
@ -313,8 +308,8 @@ int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent,
assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss);
int rv = 0;
X509_ALGOR *maskHash;
RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash);
X509_ALGOR *maskHash = NULL;
RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg);
if (!pss) {
if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) {
goto err;
@ -344,17 +339,17 @@ int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent,
}
if (pss->maskGenAlgorithm) {
if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
BIO_puts(bp, " with ") <= 0) {
goto err;
}
if (maskHash) {
if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
maskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
if (maskHash == NULL) {
if (BIO_puts(bp, "INVALID") <= 0) {
goto err;
}
} else {
if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
BIO_puts(bp, " with ") <= 0 ||
i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
goto err;
}
} else if (BIO_puts(bp, "INVALID") <= 0) {
goto err;
}
} else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) {
goto err;

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICpTCCAY2gAwIBAgIBADANBgkqhkiG9w0BAQowADAUMRIwEAYDVQQDDAlCb3Jp
bmdTU0wwIhgPMDAwMDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowFDESMBAG
A1UEAwwJQm9yaW5nU1NMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
ugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBcHprZ5BkW
f6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepBrhtp5UQS
jHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aNlcMj6MYy
8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65LUduTL50
+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19WJH4PrFwk
7ZE1QJQQ1L4iKmPeQistuQIDAQABMA0GCSqGSIb3DQEBCjAAA4IBAQAQvYDcDDNx
QPctGNiZTH9N2I2wdVXHmsybRW7tXWVYm+yE8IzfVUUBkCL5WvbLxlujMAbQpHp8
EnKECVsNAklHAAQ6KFDTngyDAjdyGiNKKMm37UW/I7BkdFZE+jBYKoVU5xeLSPm1
jNKQWqjGnaZ+wV7Fl8Zy+QOr7Z35zrDNbCF/EkzoE6+i/bbqXIgu5x14rj9c4JAs
aKPpTtpDI1zt9BfGMPsBxsxeckqnG8OlNc6YI8svAK849naTAPx93jDWmDBYqfsb
MeZOo9+AfUP7pjoDZHsQCmPdmlDgAtMvi8K1oFbw4BBTu+CaCzhNS5xEbITef09i
tjiySH0Q5r01
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIC/TCCAbmgAwIBAgIBADA5BgkqhkiG9w0BAQowLKALMAkGBSsOAwIaBQChGDAW
BgkqhkiG9w0BAQgwCQYFKw4DAhoFAKIDAgEUMBQxEjAQBgNVBAMMCUJvcmluZ1NT
TDAiGA8wMDAwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAUMRIwEAYDVQQD
DAlCb3JpbmdTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6C9qE
GRIBQXV8Lj29vVu+U+tyXzSSinWIumK5ijPhCm3DLnv4RayxkFwemtnkGRZ/o94Z
nsXkBfU/IlsYdkuq8wK9WI/ql3gwWjH+KARIhIQcSLGiJcLN6kGuG2nlRBKMcPgP
iEq2B0yBXFf4tG3CBbeae7+8G7uvOmv8NLyKj32neWpnUCTL5o2VwyPoxjLxT5gU
R69v9XSVFj2irCZbsEedeKSb++LqyMhLfnRTzNv+ZHNh4izZHrktR25MvnT5QyBq
32hx7AjZ2/xo70OmH7w10a2DwsVjJNMdxTEmgyvU9M6CeYRPX1Ykfg+sXCTtkTVA
lBDUviIqY95CKy25AgMBAAEwOQYJKoZIhvcNAQEKMCygCzAJBgUrDgMCGgUAoRgw
FgYJKoZIhvcNAQEIMAkGBSsOAwIaBQCiAwIBFAOCAQEATo0Z3YqPt4fzBXz22vyH
7Ckr1cicKTeE3lV8LYHII4easVkueN7HrfrpTPu04kn4Y8pjprh0gRj9vcf6i6Sj
khPnfmXTTbeFxHs763BQVAOoutgteyUhBZ5UjqaXnnF7PYhyG/0ykxWryvius+dz
ujhW9T0aPo95GWITtj1NHzGmCjQYqUSrfkJynC8c/juTo3MLWrMnirDsAYizTg4W
CWBfeMKRfAH6aOybSBNZh7/KU+ZiFPKJi+NKPPaZNZa0l1JZ46LL1NWVq6bybZH8
ncNZpooQKTfCaK221pbqxx4YIJT0NoICU8291LSNLz8/5uBkjUo744cF4tuNFZ4k
sg==
-----END CERTIFICATE-----

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICxzCCAZ6gAwIBAgIBADAeBgkqhkiG9w0BAQowEaEPMA0GCSqGSIb3DQEBCDAA
MBQxEjAQBgNVBAMMCUJvcmluZ1NTTDAiGA8wMDAwMDEwMTAwMDAwMFoYDzk5OTkx
MjMxMjM1OTU5WjAUMRIwEAYDVQQDDAlCb3JpbmdTU0wwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQC6C9qEGRIBQXV8Lj29vVu+U+tyXzSSinWIumK5ijPh
Cm3DLnv4RayxkFwemtnkGRZ/o94ZnsXkBfU/IlsYdkuq8wK9WI/ql3gwWjH+KARI
hIQcSLGiJcLN6kGuG2nlRBKMcPgPiEq2B0yBXFf4tG3CBbeae7+8G7uvOmv8NLyK
j32neWpnUCTL5o2VwyPoxjLxT5gUR69v9XSVFj2irCZbsEedeKSb++LqyMhLfnRT
zNv+ZHNh4izZHrktR25MvnT5QyBq32hx7AjZ2/xo70OmH7w10a2DwsVjJNMdxTEm
gyvU9M6CeYRPX1Ykfg+sXCTtkTVAlBDUviIqY95CKy25AgMBAAEwHgYJKoZIhvcN
AQEKMBGhDzANBgkqhkiG9w0BAQgwAAOCAQEANdpvRLqZLsYfruBHXjviZaKoHeoQ
1ixqeSLzcP0KzWRT3H3tX46KuYABaMurK0yPMDfW6oLCfJa3fUFt0FYJYnf/w7mp
MsmOf+7aaY8oYqI6wRwtAB0JQcC2tKsio+UEiI6hZq2ghhGa5c+YLXhN4Dt+/cK9
UkisKL4O61jKulfaErOsUSaYTo9/PJpPcUhE/zVtsfAGJH0ojSCrSpEYv4TNO9Qm
WOJ4hMreEOLVxw4xC65wRmOWl4JpGxle1mNzjsL4kOcDwsnepEOcpAqJronQ+HnI
1RCR04oEnOOWYAtFxuWzTds3BjszGPRSu3srGZpaI1j/kB+a3g/7hXufOA==
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCBAUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCBAUAogMCARwwFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCBAUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCBAUAogMCARwDggEB
AHttVo+XfLdlRXHc59yGAr7wQgqIbWOD6QSo4Tb4XbAh4nc9MQhccfT4YOMyHa9I
i1VyE9e2dna8gt9VfIyCeTnNS1RYbKagaUzo2dt/G0lQjfXRVkB1yobJEaAzZ8kg
cbknjlrlMEtHW+ET2vTHKvOjHjHXy3GYt8ynSldnotikqVobW5Kd/nYR7s9SR1Yz
VhweDRcWeb3IYSAx953t1voky/7pTltcyb5FfJLIPmj2AsoFSRnXrj1Sx0K+S68m
E0TdKwOTr2QN9nmHrIbCIeiAVeBlIOY6jH8TjobwFV2Y3RlqC+8S+Vgje/Hg/jrV
Q9fS9+RIVSOFZiOgW/1hjAA=
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAwFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASADggEB
ALVhRTv78XF2RjMusWAuTknDWkju6uvtq+iTpwCWaJO2QA2L3spEiUw52PsW9gQW
AIOttLlgQFPD3dt3OL0FBK5y79Rh/h/mrOpwbVoMOHSsgikVZhbQ0D30Y8LQYMTD
cxDYgPbnI4Q1VatdcCR8aavSDfV4JGPpJPkz8QX6HaFAoCUAz5UhiiS3MT8IzucO
nNOV7AH9yfWDfvCWDGyuIYphjFZ761VjZFFIGJuXZ9uDXDDjNxlLwO7sci/pwO89
OiRM40RxkS9vl8MjIsFSMGXOR+mf+FNtQ2vF1ZqCVxPWFuHHwmXycqrLuY3fOboF
tF5Q3O1V7sh5Bs47h29KbQU=
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFzCCAcagAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASCjAwIBATAUMRIwEAYD
VQQDDAlCb3JpbmdTU0wwIhgPMDAwMDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1
OVowFDESMBAGA1UEAwwJQm9yaW5nU1NMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWs
sZBcHprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXC
zepBrhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Ak
y+aNlcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs
2R65LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmE
T19WJH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABMEYGCSqGSIb3DQEBCjA5oA8w
DQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAIBBQCiAwIB
IKMDAgEBA4IBAQA6p/W2ZA06aYzRXL1v/VnU11udk5+UIbGAuhSVv9a+zJ4/79UX
Xk4/otg74fq/Ayy3hPm9lcOTGbXYHSgY4eFR8J1VS/P2ZPRCyypXwLSYg+Yt5Fdc
SaA2JVF2jrgMbIAzBsyz4CCOzajcF/he8+NmH7pDZhLGv4pIWaFqAPrGntIpPwVW
Qib62z9qzeexXIm+1Jp3nh21sXLbWdBM5tt5NNqST+cgzzrRnPtwQTbdcKk9i4Jh
3/BairkWclVHxibtNPoLvhU91tJw61rES29x3vG//7WwEoT2aLCkp9/ZHrM5ukpe
RxWXU+JZXiO59WWDCdK0YAuoteozepn4Cwei
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCASAwFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCASADggEB
AFMuNrMzLKfCvjDw35e5aoOPsTHKmkreUl4yHjUxX3i0heSkvy3FFcXhGjOscySF
hBoAZU1DJaIHGzq2/k9Z3pk+NFhLg6tlHvLgcySHl4kR4sqTceJeOgy4RHJU04Gv
wFAfRXx8QTJr1d00EPBoSnj7afDtvcRkzDSsgQ+YiQ9zjvt+uzuhZ25CUw8KY+Xy
CZqQYE5yIMMRoKZExPcXuWTD8Ho5pVxjeLv2+nEO73NaAP0FwisCuY98ng0ffTgG
5biORaDLzoTQv0QXtHS5TRUd6ycQ7nW28M4U1ZP9s9gj1zl+emvmi1UjNs3bcRW3
Jk0lRwKo8awDUhfWJ/YPIns=
-----END CERTIFICATE-----

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC8zCCAbSgAwIBAgIBADA0BgkqhkiG9w0BAQowJ6APMA0GCWCGSAFlAwQCAQUA
oQ8wDQYJKoZIhvcNAQEIMACiAwIBIDAUMRIwEAYDVQQDDAlCb3JpbmdTU0wwIhgP
MDAwMDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowFDESMBAGA1UEAwwJQm9y
aW5nU1NMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAugvahBkSAUF1
fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBcHprZ5BkWf6PeGZ7F5AX1
PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepBrhtp5UQSjHD4D4hKtgdM
gVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aNlcMj6MYy8U+YFEevb/V0
lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65LUduTL50+UMgat9ocewI
2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19WJH4PrFwk7ZE1QJQQ1L4i
KmPeQistuQIDAQABMDQGCSqGSIb3DQEBCjAnoA8wDQYJYIZIAWUDBAIBBQChDzAN
BgkqhkiG9w0BAQgwAKIDAgEgA4IBAQAJ0RuKq+OgFlcm2EMk+VXH8hSo87N3wcyK
9SzLwONh2uVYR3W1ig+/EwqK0M9w5UwvSVNdFa3m2qVXApprUm7eCJ2c7rWiBkQy
sVCHwWVCseItZ8ipJHHz0uC5k3EFBSVbsbRdTJ8FPbRDBXXn2iSz6OzUJVZ5PfV1
XRC81Aoi8DbhFwNga7/mJ80Ru4UGEePT6SsyUU5sgZ0w37r+5VPQgL4oOMO2NKz+
O060CbcDcOXrCm1x0BXIOc7gZEao5mriJTFQTq4PsuMnJ9a7aU+PYPfTxptr/VxB
yJJSi0sjTpqmWKStBjeZlEYq57nWZLmueA9xf8T1Ah6WRDRFo8m1
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBTCCAb2gAwIBAgIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa
MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIDAUMRIwEAYDVQQDDAlCb3Jp
bmdTU0wwIhgPMDAwMDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowFDESMBAG
A1UEAwwJQm9yaW5nU1NMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
ugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBcHprZ5BkW
f6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepBrhtp5UQS
jHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aNlcMj6MYy
8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65LUduTL50
+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19WJH4PrFwk
7ZE1QJQQ1L4iKmPeQistuQIDAQABMD0GCSqGSIb3DQEBCjAwoA0wCwYJYIZIAWUD
BAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIDAgEgA4IBAQAss/sOR0J5
rAmctg1qnUYeUKr3RN2MTAb58ZsbE9Gvjr4lgdRo4ADIwqfKYcEe3Xms0WO8gAle
efbzrcqM1wZ6wjdcZEI9xz2L5moX0lD40Jd18OFe4wrmt7eMCaz+gTdHx+5uQy53
4H+Vw6IUeO9m1K1wqDkwsiPWv22FqKghD07wKiNR7bkPnQDERRRN6UliCFfMEXOx
h9IbYJQUIVvBFqkI9C/lKbrmxdS7fv3wFnu61knkh7JNIXXWNdYHHRDqNDZOhakn
0wf3qY359CofKk+9kg/9cj1lP8HwgATxL69pBmSvM7O6ybDRhp4+/oySQCbcOIfs
IOo8AoyPo4u2
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCAR8wFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCAR8DggEB
ACRCt8NtcKkDg86ub1PiWSws4b/5v9ujPbatTrocCOXnob3Z4dnHKpjeUC0et/ex
s4hlluZ9WHb+WgR5LP7I1eIE5C1RIL5aVLguSBi8/qQICNVgeMvZSgv/mDJ0eiv2
xztcYlDwANPIh2RDpVyD6qUphvH8W6vrd6mo3aYgegigaDr/8d01MZh5s4120iWn
+8XKXNep8YqLhYemn3WeXtvK4vEEdFln6WeRRlGKevX9LqOegshs8HgKjjYRH++I
c5HtwRZFkkMnXOV0XyG5zPrsx0qDcJCGHrC20bM+ZZz60QOtb1BSMIS5KjMy5OPQ
bueM0YwX72tPKox+3lJgXAk=
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDGzCCAcigAwIBAgIBADBIBgkqhkiG9w0BAQowO6APMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogoCCEAAAAAAAAAgMBQxEjAQ
BgNVBAMMCUJvcmluZ1NTTDAiGA8wMDAwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1
OTU5WjAUMRIwEAYDVQQDDAlCb3JpbmdTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC6C9qEGRIBQXV8Lj29vVu+U+tyXzSSinWIumK5ijPhCm3DLnv4
RayxkFwemtnkGRZ/o94ZnsXkBfU/IlsYdkuq8wK9WI/ql3gwWjH+KARIhIQcSLGi
JcLN6kGuG2nlRBKMcPgPiEq2B0yBXFf4tG3CBbeae7+8G7uvOmv8NLyKj32neWpn
UCTL5o2VwyPoxjLxT5gUR69v9XSVFj2irCZbsEedeKSb++LqyMhLfnRTzNv+ZHNh
4izZHrktR25MvnT5QyBq32hx7AjZ2/xo70OmH7w10a2DwsVjJNMdxTEmgyvU9M6C
eYRPX1Ykfg+sXCTtkTVAlBDUviIqY95CKy25AgMBAAEwSAYJKoZIhvcNAQEKMDug
DzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIK
AghAAAAAAAAAIAOCAQEAn7ufGUhwZUfP13AEXFZGo7tpWYKbiDpVnHTtj/21/SWd
TXP1LJWIJuo8pGs/ZsXI+XoXJMk01G1wVPPUny/D7T9WXLW191UFzIGO0bJZIfv2
M9YbRkTsCiAYUuyFUlwwSLMqMXrZjRXlgulv3DjWrDHrAqfst847Ety24P1uYG7C
m4JV8Sa0SIKRntd00YYmk6oUZNgEzUps7moLsOEox3U2s6wTipl/++9H5CI5mQTS
fdGMRzEsuJRfXkgMccEfDw2wvNfmNzILGDsvxjCilkEisuMPxlRptSk5agYFujAW
D3QjJGCgGlSXhN3JuH9S2/0N5gRQpN/98beTTXpxvg==
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDEzCCAcSgAwIBAgIBADBEBgkqhkiG9w0BAQowN6APMA0GCWCGSAFlAwQCAQUA
oR8wHQYMKoZIhvcSBAGEtwkAMA0GCWCGSAFlAwQCAQUAogMCASAwFDESMBAGA1UE
AwwJQm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTla
MBQxEjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQ
XB6a2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3q
Qa4baeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvm
jZXDI+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNke
uS1Hbky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9f
ViR+D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBEBgkqhkiG9w0BAQowN6APMA0G
CWCGSAFlAwQCAQUAoR8wHQYMKoZIhvcSBAGEtwkAMA0GCWCGSAFlAwQCAQUAogMC
ASADggEBACdP7ToiiM+6TqeAbKRqsPuFX9Q0qJtjX8mGVyzOEy402hEhglMeL9il
FFFKCgo/wux4VIbw7BVLFDfYPcj8E7snj+J0mITIFt5oCwXG+MrJUnfklBEEyelF
kVyr1ZVIwsk/lWSaOcQocbx8/szRRhwwVTT7BySnMV4e/y7Z9beye6tl7lg4373K
E4akVubalnkoTHP5fZ6f0AfOXJEnLw2Mn0zjwrZmasMyXxLH8ApUVruPBQHY7IQB
sMAURzkRtcCyzhQniJFcu7oMmkj+v8FVG02792DOWP+Y/yC0ccmHcvDbdzJW5SDm
rBvNkmnPt6sYs7/RLRaVky7cRMAQrFs=
-----END CERTIFICATE-----

@ -0,0 +1,22 @@
This certificate has a trailerField of 2, but the signature was still
generated with the standard 0xbc suffix.
-----BEGIN CERTIFICATE-----
MIIDFzCCAcagAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAQUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASCjAwIBAjAUMRIwEAYD
VQQDDAlCb3JpbmdTU0wwIhgPMDAwMDAxMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1
OVowFDESMBAGA1UEAwwJQm9yaW5nU1NMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWs
sZBcHprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXC
zepBrhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Ak
y+aNlcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs
2R65LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmE
T19WJH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABMEYGCSqGSIb3DQEBCjA5oA8w
DQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAIBBQCiAwIB
IKMDAgECA4IBAQCVtDpbDRnbn7UQd8sPq+XSHk2nwvlhwSKZ0XZ0vwBGkNuhO/SY
BhVUez+uGxXnJE+MkVAAh3NOdEQV6apEX5tymCyB0vqwLQB86gANOt82kF/tOW4M
Sv5f6L8GJbYtpTd/cyAMEs7U/X9O5W1G9sLINWeukUYHPVKjj/tE3NfLCE8SWlw4
SCnbuhs5WXnEgUP/9JgL8xyI6bxn9E2OUvqD+U24k0PbtAdk09697gUYUDQlmxi6
MRoQYKTezNJt4DXRhqUlokWiF5D42MaMz5WXtLQaBfbqQB6n1Ln+hTaGwWP6xNSm
Mip0TYOwAQdcTvr8UoQUJR/90SX+S4m6cu4d
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAgUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATAwFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCAgUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATADggEB
AASUWBIEjb0TkXJKhj3RNRRe0D+KWFpyAn/kdBgDce/LEQVywj8IeS+s9z9TcGEK
iKr8tPIsNUM1agj3gd1zWuM5rbUABQyGzeWcfjmhmhK5mnCSOu/OD+DJjWqyHpQq
/Qf2djrpXJXKVNoSBzci4KUpFIfKMT4KjnUKY9L8lxfl9zaPeIaFeXgtyhHYnpjX
vyomoLaL3cXeeKIffgPa9s9QZGx2fKOnFmcS3eKL9pIcj4Z6K8+Nchg6Z2qYKWtM
hH1ZFlNDC3VOPgNkHoBrU6gE5fQv6lO64egL9pM0bpaOi7drhHKjkw2URi4C9KGK
P9GfRmqV9Y9UlJsLSGIghxs=
-----END CERTIFICATE-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDTCCAcGgAwIBAgIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAwUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAwUAogMCAUAwFDESMBAGA1UEAwwJ
Qm9yaW5nU1NMMCIYDzAwMDAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQx
EjAQBgNVBAMMCUJvcmluZ1NTTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALoL2oQZEgFBdXwuPb29W75T63JfNJKKdYi6YrmKM+EKbcMue/hFrLGQXB6a
2eQZFn+j3hmexeQF9T8iWxh2S6rzAr1Yj+qXeDBaMf4oBEiEhBxIsaIlws3qQa4b
aeVEEoxw+A+ISrYHTIFcV/i0bcIFt5p7v7wbu686a/w0vIqPfad5amdQJMvmjZXD
I+jGMvFPmBRHr2/1dJUWPaKsJluwR514pJv74urIyEt+dFPM2/5kc2HiLNkeuS1H
bky+dPlDIGrfaHHsCNnb/GjvQ6YfvDXRrYPCxWMk0x3FMSaDK9T0zoJ5hE9fViR+
D6xcJO2RNUCUENS+Iipj3kIrLbkCAwEAATBBBgkqhkiG9w0BAQowNKAPMA0GCWCG
SAFlAwQCAwUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAwUAogMCAUADggEB
ADwQHPC6MMvgBBfgYHRvcdQqfzPb3I9HJa+Y01BAIAeICadmyB389cjhv9X1mFi9
xJOhsuek71D4YrOghExMbGXIAlalAq/rQHTzXV6cqiSrbUmmvsLmlilOeODIjuUC
z3Ldc5LvwU8nima46jP/ryMYaIjCpbNsH/MzAbYO/CNm8osjeJoKhGyozkj9tr2T
JaSFe5icta2WHfjfLP7wSkIf3NdfXNkBIBKMdHCuiEgeUeSColpgAFfngFKIJ3EG
EbgptjPoePJ0T6VOdwzSX+QhGLabaOiX0ptrhAwuCNHVAKuf5wCWKvl6mYgBaDfB
YFmL46BAX2ghB+WM/FSizPs=
-----END CERTIFICATE-----

@ -184,26 +184,6 @@ DSLfRgaQwcb2gg2xpDFoG+W0vc6O651uF23WGt5JaFFJJxqjII05IexfCNhuPmp4
-----END CERTIFICATE-----
)";
// kExamplePSSCert is an example RSA-PSS self-signed certificate, signed with
// the default hash functions.
static const char kExamplePSSCert[] = R"(
-----BEGIN CERTIFICATE-----
MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL
MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy
bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5
NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK
DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8
0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3
13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO
MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ
QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC
AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w
xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN
Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=
-----END CERTIFICATE-----
)";
// kBadPSSCertPEM is a self-signed RSA-PSS certificate with bad parameters.
static const char kBadPSSCertPEM[] = R"(
-----BEGIN CERTIFICATE-----
@ -1750,13 +1730,46 @@ TEST(X509Test, PrintGeneralName) {
}
TEST(X509Test, TestPSS) {
bssl::UniquePtr<X509> cert(CertFromPEM(kExamplePSSCert));
ASSERT_TRUE(cert);
bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(cert.get()));
ASSERT_TRUE(pkey);
static const char *kGoodCerts[] = {
"crypto/x509/test/pss_sha256.pem",
"crypto/x509/test/pss_sha384.pem",
"crypto/x509/test/pss_sha512.pem",
// We accept inputs with and without explicit NULLs. See RFC 4055,
// section 2.1.
"crypto/x509/test/pss_sha256_omit_nulls.pem",
// Although invalid, we tolerate an explicit trailerField value. See the
// certificates in cl/362617931.
"crypto/x509/test/pss_sha256_explicit_trailer.pem",
};
for (const char *path : kGoodCerts) {
SCOPED_TRACE(path);
bssl::UniquePtr<X509> cert = CertFromPEM(GetTestData(path).c_str());
ASSERT_TRUE(cert);
bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(cert.get()));
ASSERT_TRUE(pkey);
EXPECT_TRUE(X509_verify(cert.get(), pkey.get()));
}
ASSERT_TRUE(X509_verify(cert.get(), pkey.get()));
static const char *kBadCerts[] = {
"crypto/x509/test/pss_sha1_explicit.pem",
"crypto/x509/test/pss_sha1_mgf1_syntax_error.pem",
"crypto/x509/test/pss_sha1.pem",
"crypto/x509/test/pss_sha224.pem",
"crypto/x509/test/pss_sha256_mgf1_sha384.pem",
"crypto/x509/test/pss_sha256_mgf1_syntax_error.pem",
"crypto/x509/test/pss_sha256_salt_overflow.pem",
"crypto/x509/test/pss_sha256_salt31.pem",
"crypto/x509/test/pss_sha256_unknown_mgf.pem",
"crypto/x509/test/pss_sha256_wrong_trailer.pem",
};
for (const char *path : kBadCerts) {
SCOPED_TRACE(path);
bssl::UniquePtr<X509> cert = CertFromPEM(GetTestData(path).c_str());
ASSERT_TRUE(cert);
bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(cert.get()));
ASSERT_TRUE(pkey);
EXPECT_FALSE(X509_verify(cert.get(), pkey.get()));
}
}
TEST(X509Test, TestPSSBadParameters) {
@ -1857,30 +1870,53 @@ TEST(X509Test, RSASign) {
EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()));
ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pkey.get()));
// Test RSA-PSS with custom parameters.
// RSA-PSS with salt length matching hash length should work when passing in
// -1 or the value explicitly.
md_ctx.Reset();
EVP_PKEY_CTX *pkey_ctx;
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1));
ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pkey.get()));
// RSA-PSS with salt length matching hash length should work when passing in
// -1 or the value explicitly.
md_ctx.Reset();
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, 32));
ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pkey.get()));
// RSA-PSS with SHA-1 is not supported.
md_ctx.Reset();
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), NULL,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1));
bssl::UniquePtr<X509> cert = CertFromPEM(kLeafPEM);
ASSERT_TRUE(cert);
EXPECT_FALSE(X509_sign_ctx(cert.get(), md_ctx.get()));
// RSA-PSS with mismatched hashes is not supported.
md_ctx.Reset();
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, 32));
ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()));
cert = CertFromPEM(kLeafPEM);
ASSERT_TRUE(cert);
EXPECT_FALSE(X509_sign_ctx(cert.get(), md_ctx.get()));
// RSA-PSS with the wrong salt length is not supported.
md_ctx.Reset();
ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
pkey.get()));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, 33));
cert = CertFromPEM(kLeafPEM);
ASSERT_TRUE(cert);
EXPECT_FALSE(X509_sign_ctx(cert.get(), md_ctx.get()));
}
// Test the APIs for manually signing a certificate.

@ -102,6 +102,21 @@ set(
crypto/x509/test/many_names1.pem
crypto/x509/test/many_names2.pem
crypto/x509/test/many_names3.pem
crypto/x509/test/pss_sha1_explicit.pem
crypto/x509/test/pss_sha1_mgf1_syntax_error.pem
crypto/x509/test/pss_sha1.pem
crypto/x509/test/pss_sha224.pem
crypto/x509/test/pss_sha256_explicit_trailer.pem
crypto/x509/test/pss_sha256_mgf1_sha384.pem
crypto/x509/test/pss_sha256_mgf1_syntax_error.pem
crypto/x509/test/pss_sha256_omit_nulls.pem
crypto/x509/test/pss_sha256_salt_overflow.pem
crypto/x509/test/pss_sha256_salt31.pem
crypto/x509/test/pss_sha256_unknown_mgf.pem
crypto/x509/test/pss_sha256_wrong_trailer.pem
crypto/x509/test/pss_sha256.pem
crypto/x509/test/pss_sha384.pem
crypto/x509/test/pss_sha512.pem
crypto/x509/test/some_names1.pem
crypto/x509/test/some_names2.pem
crypto/x509/test/some_names3.pem

Loading…
Cancel
Save