mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-10-24 04:09:07 +03:00
6078 lines
259 KiB
C
6078 lines
259 KiB
C
/* test_asn.c
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <tests/unit.h>
|
|
|
|
#include <tests/api/api.h>
|
|
#include <tests/api/test_asn.h>
|
|
|
|
#include <wolfssl/wolfcrypt/asn.h>
|
|
#include <wolfssl/wolfcrypt/asn_public.h>
|
|
#include <wolfssl/wolfcrypt/random.h>
|
|
#include <wolfssl/wolfcrypt/rsa.h>
|
|
#ifdef HAVE_ED25519
|
|
#include <wolfssl/wolfcrypt/ed25519.h>
|
|
#endif
|
|
#ifdef HAVE_ED448
|
|
#include <wolfssl/wolfcrypt/ed448.h>
|
|
#endif
|
|
#ifdef HAVE_ECC
|
|
#include <wolfssl/wolfcrypt/ecc.h>
|
|
#endif
|
|
#ifdef HAVE_DILITHIUM
|
|
#include <wolfssl/wolfcrypt/dilithium.h>
|
|
#endif
|
|
|
|
#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
|
|
static int test_SetAsymKeyDer_once(byte* privKey, word32 privKeySz, byte* pubKey,
|
|
word32 pubKeySz, byte* trueDer, word32 trueDerSz)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
byte* calcDer = NULL;
|
|
word32 calcDerSz = 0;
|
|
|
|
ExpectIntEQ(calcDerSz = SetAsymKeyDer(privKey, privKeySz, pubKey, pubKeySz,
|
|
NULL, 0, ED25519k), trueDerSz);
|
|
ExpectNotNull(calcDer = (byte*)XMALLOC(calcDerSz, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
ExpectIntEQ(calcDerSz = SetAsymKeyDer(privKey, privKeySz, pubKey, pubKeySz,
|
|
calcDer, calcDerSz, ED25519k), trueDerSz);
|
|
ExpectIntEQ(XMEMCMP(calcDer, trueDer, trueDerSz), 0);
|
|
XFREE(calcDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
#endif /* WC_ENABLE_ASYM_KEY_EXPORT && HAVE_ED25519 */
|
|
|
|
int test_SetAsymKeyDer(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
|
|
/* We can't access the keyEd25519Oid variable, so declare it instead */
|
|
byte algId[] = {43, 101, 112};
|
|
/* RFC 5958: version is v1 (0) for private only, v2 (1) when public key
|
|
* bundled. Conditions 1-5 are private only, 6-8 include pub key and
|
|
* mutate version[0] = 0x1 before building trueDer. */
|
|
byte version[] = {0x0};
|
|
byte keyPat = 0xcc;
|
|
|
|
byte* privKey = NULL;
|
|
word32 privKeySz = 0;
|
|
byte* pubKey = NULL;
|
|
word32 pubKeySz = 0;
|
|
byte trueDer[310]; /* The largest size is 310 bytes on Condition 8 */
|
|
word32 trueDerSz = 0;
|
|
|
|
/*
|
|
* Condition 1:
|
|
* PKEY data = 34 (1 to 127)
|
|
* PKEY_CURVEPKEY data = 32 (1 to 127)
|
|
* PUBKEY data = 0 (Empty)
|
|
* SEQ data = 46 (1 to 127)
|
|
*/
|
|
privKeySz = 32;
|
|
pubKeySz = 0;
|
|
trueDerSz = 48;
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = trueDerSz - 2;
|
|
/* VER */
|
|
trueDer[2] = ASN_INTEGER;
|
|
trueDer[3] = sizeof(version);
|
|
trueDer[4] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[5] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[6] = sizeof(algId) + 2;
|
|
trueDer[7] = ASN_OBJECT_ID;
|
|
trueDer[8] = sizeof(algId);
|
|
trueDer[9] = algId[0];
|
|
trueDer[10] = algId[1];
|
|
trueDer[11] = algId[2];
|
|
/* PKEY */
|
|
trueDer[12] = ASN_OCTET_STRING;
|
|
trueDer[13] = privKeySz + 2;
|
|
trueDer[14] = ASN_OCTET_STRING;
|
|
trueDer[15] = privKeySz;
|
|
privKey = &trueDer[16];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[16] to trueDer[47] */
|
|
/* PUBKEY */
|
|
pubKey = NULL; /* Empty */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 2:
|
|
* PKEY data = 129 (128 to 255)
|
|
* PKEY_CURVEKEY data = 127 (0 to 127)
|
|
* PUBKEY data = 0 (Empty)
|
|
* SEQ data = 142 (128 to 255)
|
|
*/
|
|
privKeySz = 127;
|
|
pubKeySz = 0;
|
|
trueDerSz = 145;
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x81;
|
|
trueDer[2] = trueDerSz - 3;
|
|
/* VER */
|
|
trueDer[3] = ASN_INTEGER;
|
|
trueDer[4] = sizeof(version);
|
|
trueDer[5] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[6] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[7] = sizeof(algId) + 2;
|
|
trueDer[8] = ASN_OBJECT_ID;
|
|
trueDer[9] = sizeof(algId);
|
|
trueDer[10] = algId[0];
|
|
trueDer[11] = algId[1];
|
|
trueDer[12] = algId[2];
|
|
/* PKEY */
|
|
trueDer[13] = ASN_OCTET_STRING;
|
|
trueDer[14] = 0x81;
|
|
trueDer[15] = privKeySz + 2;
|
|
trueDer[16] = ASN_OCTET_STRING;
|
|
trueDer[17] = privKeySz;
|
|
privKey = &trueDer[18];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[18] to trueDer[144] */
|
|
/* PUBKEY */
|
|
pubKey = NULL; /* Empty */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 3:
|
|
* PKEY data = 131 (128 to 255)
|
|
* PKEY_CURVEKEY = 128 (128 to 255)
|
|
* PUBKEY data = 0 (Empty)
|
|
* SEQ data =144 (128 to 255)
|
|
*/
|
|
privKeySz = 128;
|
|
pubKeySz = 0;
|
|
trueDerSz = 147;
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x81;
|
|
trueDer[2] = trueDerSz - 3;
|
|
/* VER */
|
|
trueDer[3] = ASN_INTEGER;
|
|
trueDer[4] = sizeof(version);
|
|
trueDer[5] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[6] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[7] = sizeof(algId) + 2;
|
|
trueDer[8] = ASN_OBJECT_ID;
|
|
trueDer[9] = sizeof(algId);
|
|
trueDer[10] = algId[0];
|
|
trueDer[11] = algId[1];
|
|
trueDer[12] = algId[2];
|
|
/* PKEY */
|
|
trueDer[13] = ASN_OCTET_STRING;
|
|
trueDer[14] = 0x81;
|
|
trueDer[15] = privKeySz + 3;
|
|
trueDer[16] = ASN_OCTET_STRING;
|
|
trueDer[17] = 0x81;
|
|
trueDer[18] = privKeySz;
|
|
privKey = &trueDer[19];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[19] to trueDer[146] */
|
|
/* PUBKEY */
|
|
pubKey = NULL; /* Empty */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 4:
|
|
* PKEY data = 258 (256 to 65535)
|
|
* PKEY_CURVEPKEY data = 255 (128 to 255)
|
|
* PUBKEY data = 0 (Empty)
|
|
* SEQ data = 272 (256 to 65536)
|
|
*/
|
|
privKeySz = 255;
|
|
pubKeySz = 0;
|
|
trueDerSz = 276;
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x82;
|
|
trueDer[2] = ((trueDerSz - 4) >> 8) & 0xff;
|
|
trueDer[3] = (trueDerSz - 4) & 0xff;
|
|
/* VER */
|
|
trueDer[4] = ASN_INTEGER;
|
|
trueDer[5] = sizeof(version);
|
|
trueDer[6] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[7] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[8] = sizeof(algId) + 2;
|
|
trueDer[9] = ASN_OBJECT_ID;
|
|
trueDer[10] = sizeof(algId);
|
|
trueDer[11] = algId[0];
|
|
trueDer[12] = algId[1];
|
|
trueDer[13] = algId[2];
|
|
/* PKEY */
|
|
trueDer[14] = ASN_OCTET_STRING;
|
|
trueDer[15] = 0x82;
|
|
trueDer[16] = ((privKeySz + 3) >> 8) & 0xff;
|
|
trueDer[17] = (privKeySz + 3) & 0xff;
|
|
trueDer[18] = ASN_OCTET_STRING;
|
|
trueDer[19] = 0x81;
|
|
trueDer[20] = privKeySz;
|
|
privKey = &trueDer[21];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[21] to trueDer[275] */
|
|
/* PUBKEY */
|
|
pubKey = NULL; /* Empty */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 5:
|
|
* PKEY data = 260 (256 to 65535)
|
|
* PKEY_CURVEPKEY data = 256 (256 to 65535)
|
|
* PUBKEY data = 0 (Empty)
|
|
* SEQ data = 274 (256 to 65535)
|
|
*/
|
|
privKeySz = 256;
|
|
pubKeySz = 0;
|
|
trueDerSz = 278;
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x82;
|
|
trueDer[2] = ((trueDerSz - 4) >> 8) & 0xff;
|
|
trueDer[3] = (trueDerSz - 4) & 0xff;
|
|
/* VER */
|
|
trueDer[4] = ASN_INTEGER;
|
|
trueDer[5] = sizeof(version);
|
|
trueDer[6] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[7] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[8] = sizeof(algId) + 2;
|
|
trueDer[9] = ASN_OBJECT_ID;
|
|
trueDer[10] = sizeof(algId);
|
|
trueDer[11] = algId[0];
|
|
trueDer[12] = algId[1];
|
|
trueDer[13] = algId[2];
|
|
/* PKEY */
|
|
trueDer[14] = ASN_OCTET_STRING;
|
|
trueDer[15] = 0x82;
|
|
trueDer[16] = ((privKeySz + 4) >> 8) & 0xff;
|
|
trueDer[17] = (privKeySz + 4) & 0xff;
|
|
trueDer[18] = ASN_OCTET_STRING;
|
|
trueDer[19] = 0x82;
|
|
trueDer[20] = (privKeySz >> 8) & 0xff;
|
|
trueDer[21] = privKeySz & 0xff;
|
|
privKey = &trueDer[22];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[22] to trueDer[277] */
|
|
/* PUBKEY */
|
|
pubKey = NULL; /* Empty */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 6:
|
|
* PKEY data = 34 (1 to 127)
|
|
* PKEY_CURVEPKEY data = 32 (1 to 127)
|
|
* PUBKEY data = 32 (1 to 127)
|
|
* SEQ data = 80 (1 to 127)
|
|
*/
|
|
privKeySz = 32;
|
|
pubKeySz = 32;
|
|
trueDerSz = 82;
|
|
version[0] = 0x1; /* publicKey present (v2) */
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = trueDerSz - 2;
|
|
/* VER */
|
|
trueDer[2] = ASN_INTEGER;
|
|
trueDer[3] = sizeof(version);
|
|
trueDer[4] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[5] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[6] = sizeof(algId) + 2;
|
|
trueDer[7] = ASN_OBJECT_ID;
|
|
trueDer[8] = sizeof(algId);
|
|
trueDer[9] = algId[0];
|
|
trueDer[10] = algId[1];
|
|
trueDer[11] = algId[2];
|
|
/* PKEY */
|
|
trueDer[12] = ASN_OCTET_STRING;
|
|
trueDer[13] = privKeySz + 2;
|
|
trueDer[14] = ASN_OCTET_STRING;
|
|
trueDer[15] = privKeySz;
|
|
privKey = &trueDer[16];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[16] to trueDer[47] */
|
|
/* PUBKEY */
|
|
trueDer[48] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
|
trueDer[49] = pubKeySz;
|
|
pubKey = &trueDer[50];
|
|
XMEMSET(pubKey, keyPat, pubKeySz); /* trueDer[50] to trueDer[81] */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 7:
|
|
* PKEY data = 34 (1 to 127)
|
|
* PKEY_CURVEPKEY data = 32 (1 to 127)
|
|
* PUBKEY data = 128 (128 to 255)
|
|
* SEQ data = 180 (128 to 255)
|
|
*/
|
|
privKeySz = 32;
|
|
pubKeySz = 128;
|
|
trueDerSz = 180;
|
|
version[0] = 0x1; /* publicKey present (v2) */
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x81;
|
|
trueDer[2] = trueDerSz - 3;
|
|
/* VER */
|
|
trueDer[3] = ASN_INTEGER;
|
|
trueDer[4] = sizeof(version);
|
|
trueDer[5] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[6] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[7] = sizeof(algId) + 2;
|
|
trueDer[8] = ASN_OBJECT_ID;
|
|
trueDer[9] = sizeof(algId);
|
|
trueDer[10] = algId[0];
|
|
trueDer[11] = algId[1];
|
|
trueDer[12] = algId[2];
|
|
/* PKEY */
|
|
trueDer[13] = ASN_OCTET_STRING;
|
|
trueDer[14] = privKeySz + 2;
|
|
trueDer[15] = ASN_OCTET_STRING;
|
|
trueDer[16] = privKeySz;
|
|
privKey = &trueDer[17];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[17] to trueDer[48] */
|
|
/* PUBKEY */
|
|
trueDer[49] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
|
trueDer[50] = 0x81;
|
|
trueDer[51] = pubKeySz;
|
|
pubKey = &trueDer[52];
|
|
XMEMSET(pubKey, keyPat, pubKeySz); /* trueDer[52] to trueDer[179] */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
|
|
/*
|
|
* Condition 8:
|
|
* PKEY data = 34 (1 to 127)
|
|
* PKEY_CURVEPKEY data = 32 (1 to 127)
|
|
* PUBKEY data = 256 (256 to 65535)
|
|
* SEQ data = 306 (256 to 65535)
|
|
*/
|
|
privKeySz = 32;
|
|
pubKeySz = 256;
|
|
trueDerSz = 310;
|
|
version[0] = 0x1; /* publicKey present (v2) */
|
|
|
|
/* SEQ */
|
|
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[1] = 0x82;
|
|
trueDer[2] = ((trueDerSz - 4) >> 8) & 0xff;
|
|
trueDer[3] = (trueDerSz - 4) & 0xff;
|
|
/* VER */
|
|
trueDer[4] = ASN_INTEGER;
|
|
trueDer[5] = sizeof(version);
|
|
trueDer[6] = version[0];
|
|
/* PKEYALGO_SEQ */
|
|
trueDer[7] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
trueDer[8] = sizeof(algId) + 2;
|
|
trueDer[9] = ASN_OBJECT_ID;
|
|
trueDer[10] = sizeof(algId);
|
|
trueDer[11] = algId[0];
|
|
trueDer[12] = algId[1];
|
|
trueDer[13] = algId[2];
|
|
/* PKEY */
|
|
trueDer[14] = ASN_OCTET_STRING;
|
|
trueDer[15] = privKeySz + 2;
|
|
trueDer[16] = ASN_OCTET_STRING;
|
|
trueDer[17] = privKeySz;
|
|
privKey = &trueDer[18];
|
|
XMEMSET(privKey, keyPat, privKeySz); /* trueDer[18] to trueDer[49] */
|
|
/* PUBKEY */
|
|
trueDer[50] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
|
trueDer[51] = 0x82;
|
|
trueDer[52] = (pubKeySz >> 8) & 0xff;
|
|
trueDer[53] = pubKeySz & 0xff;
|
|
pubKey = &trueDer[54];
|
|
XMEMSET(pubKey, keyPat, pubKeySz); /* trueDer[54] to trueDer[309] */
|
|
|
|
EXPECT_TEST(test_SetAsymKeyDer_once(privKey, privKeySz, pubKey, pubKeySz,
|
|
trueDer, trueDerSz));
|
|
#endif /* WC_ENABLE_ASYM_KEY_EXPORT && HAVE_ED25519 */
|
|
|
|
return EXPECT_RESULT();
|
|
|
|
}
|
|
|
|
/* RFC 5958 leniency: parser must accept all four variants:
|
|
* {v=0,v=1} x {publicKey absent, present}. */
|
|
int test_DecodeAsymKey_lenient_versions(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
|
|
defined(HAVE_ED25519_KEY_IMPORT) && defined(WOLFSSL_KEY_GEN) && \
|
|
defined(HAVE_ED25519_MAKE_KEY)
|
|
ed25519_key key;
|
|
ed25519_key parsed;
|
|
WC_RNG rng;
|
|
byte bundled[256]; /* v=1 + publicKey */
|
|
byte privOnly[256]; /* v=0, no publicKey */
|
|
byte tmp[256];
|
|
int bundledSz = 0;
|
|
int privOnlySz = 0;
|
|
word32 idx;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
|
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
|
|
|
ExpectIntGT(bundledSz = wc_Ed25519KeyToDer(&key, bundled,
|
|
(word32)sizeof(bundled)), 0);
|
|
ExpectIntGT(privOnlySz = wc_Ed25519PrivateKeyToDer(&key, privOnly,
|
|
(word32)sizeof(privOnly)), 0);
|
|
|
|
if (EXPECT_SUCCESS() &&
|
|
((bundledSz > 0) && ((size_t)bundledSz <= sizeof(bundled)) &&
|
|
(privOnlySz > 0) && ((size_t)privOnlySz <= sizeof(privOnly)))) {
|
|
|
|
/* v=1 + publicKey */
|
|
XMEMCPY(tmp, bundled, (size_t)bundledSz);
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)bundledSz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
|
|
/* v=0 + publicKey: patch version byte, [1] publicKey field present. */
|
|
XMEMCPY(tmp, bundled, (size_t)bundledSz);
|
|
ExpectIntGT(test_pkcs8_patch_version_byte(tmp, (word32)bundledSz, 0),
|
|
0);
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)bundledSz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
|
|
/* v=0, no publicKey */
|
|
XMEMCPY(tmp, privOnly, (size_t)privOnlySz);
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)privOnlySz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
|
|
/* v=1, no publicKey */
|
|
XMEMCPY(tmp, privOnly, (size_t)privOnlySz);
|
|
ExpectIntGT(test_pkcs8_patch_version_byte(tmp, (word32)privOnlySz, 1),
|
|
0);
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)privOnlySz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
}
|
|
|
|
wc_ed25519_free(&key);
|
|
wc_FreeRng(&rng);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_DecodeAsymKey_negative(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
|
|
defined(HAVE_ED25519_KEY_IMPORT) && defined(WOLFSSL_KEY_GEN) && \
|
|
defined(HAVE_ED25519_MAKE_KEY)
|
|
ed25519_key key;
|
|
ed25519_key parsed;
|
|
WC_RNG rng;
|
|
byte good[256];
|
|
byte tmp[256];
|
|
int goodSz = 0;
|
|
word32 idx;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
|
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
|
ExpectIntGT(goodSz = wc_Ed25519KeyToDer(&key, good,
|
|
(word32)sizeof(good)), 0);
|
|
|
|
if (EXPECT_SUCCESS() &&
|
|
(goodSz > 0 && (size_t)goodSz <= sizeof(good))) {
|
|
|
|
/* Truncated buffer */
|
|
XMEMCPY(tmp, good, (size_t)goodSz);
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)(goodSz - 1)), 0);
|
|
wc_ed25519_free(&parsed);
|
|
|
|
/* Outer length too big. Patch low-order length byte (long form: bump
|
|
* the last byte of the multi-byte length encoding). */
|
|
XMEMCPY(tmp, good, (size_t)goodSz);
|
|
if ((good[1] & 0x80) == 0) {
|
|
tmp[1] = (byte)(good[1] + 1);
|
|
}
|
|
else {
|
|
word32 nBytes = (word32)(good[1] & 0x7F);
|
|
tmp[1 + nBytes] = (byte)(good[1 + nBytes] + 1);
|
|
}
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)goodSz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
|
|
/* Outer tag not SEQUENCE */
|
|
XMEMCPY(tmp, good, (size_t)goodSz);
|
|
tmp[0] = 0x02;
|
|
XMEMSET(&parsed, 0, sizeof(parsed));
|
|
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
|
|
idx = 0;
|
|
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
|
|
(word32)goodSz), 0);
|
|
wc_ed25519_free(&parsed);
|
|
}
|
|
|
|
wc_ed25519_free(&key);
|
|
wc_FreeRng(&rng);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#ifndef NO_ASN
|
|
static int test_GetSetShortInt_once(word32 val, byte* valDer, word32 valDerSz)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#ifndef NO_PWDBASED
|
|
#if !defined(WOLFSSL_ASN_TEMPLATE) || defined(HAVE_PKCS8) || \
|
|
defined(HAVE_PKCS12)
|
|
|
|
byte outDer[MAX_SHORT_SZ];
|
|
word32 outDerSz = 0;
|
|
word32 inOutIdx = 0;
|
|
word32 maxIdx = MAX_SHORT_SZ;
|
|
int value;
|
|
|
|
ExpectIntLE(2 + valDerSz, MAX_SHORT_SZ);
|
|
ExpectIntEQ(outDerSz = SetShortInt(outDer, &inOutIdx, val, maxIdx),
|
|
2 + valDerSz);
|
|
ExpectIntEQ(outDer[0], ASN_INTEGER);
|
|
ExpectIntEQ(outDer[1], valDerSz);
|
|
ExpectIntEQ(XMEMCMP(outDer + 2, valDer, valDerSz), 0);
|
|
if (val < 0x80000000) {
|
|
/* GetShortInt only supports positive values. */
|
|
inOutIdx = 0;
|
|
ExpectIntEQ(val, GetShortInt(outDer, &inOutIdx, &value, maxIdx));
|
|
}
|
|
|
|
#endif /* !WOLFSSL_ASN_TEMPLATE || HAVE_PKCS8 || HAVE_PKCS12 */
|
|
#endif /* !NO_PWDBASED */
|
|
|
|
(void)val;
|
|
(void)valDer;
|
|
(void)valDerSz;
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
#endif
|
|
|
|
int test_GetSetShortInt(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#ifndef NO_ASN
|
|
byte valDer[MAX_SHORT_SZ] = {0};
|
|
|
|
/* Corner tests for input size */
|
|
{
|
|
/* Input 1 byte min */
|
|
valDer[0] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x00, valDer, 1));
|
|
|
|
/* Input 1 byte max */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0xff, valDer, 2));
|
|
|
|
/* Input 2 bytes min */
|
|
valDer[0] = 0x01;
|
|
valDer[1] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x0100, valDer, 2));
|
|
|
|
/* Input 2 bytes max */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0xff;
|
|
valDer[2] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0xffff, valDer, 3));
|
|
|
|
/* Input 3 bytes min */
|
|
valDer[0] = 0x01;
|
|
valDer[1] = 0x00;
|
|
valDer[2] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x010000, valDer, 3));
|
|
|
|
/* Input 3 bytes max */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0xff;
|
|
valDer[2] = 0xff;
|
|
valDer[3] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0xffffff, valDer, 4));
|
|
|
|
/* Input 4 bytes min */
|
|
valDer[0] = 0x01;
|
|
valDer[1] = 0x00;
|
|
valDer[2] = 0x00;
|
|
valDer[3] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x01000000, valDer, 4));
|
|
|
|
/* Input 4 bytes max */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0xff;
|
|
valDer[2] = 0xff;
|
|
valDer[3] = 0xff;
|
|
valDer[4] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0xffffffff, valDer, 5));
|
|
}
|
|
|
|
/* Corner tests for output size */
|
|
{
|
|
/* Skip "Output 1 byte min" because of same as "Input 1 byte min" */
|
|
|
|
/* Output 1 byte max */
|
|
valDer[0] = 0x7f;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x7f, valDer, 1));
|
|
|
|
/* Output 2 bytes min */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0x80;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x80, valDer, 2));
|
|
|
|
/* Output 2 bytes max */
|
|
valDer[0] = 0x7f;
|
|
valDer[1] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x7fff, valDer, 2));
|
|
|
|
/* Output 3 bytes min */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0x80;
|
|
valDer[2] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x8000, valDer, 3));
|
|
|
|
/* Output 3 bytes max */
|
|
valDer[0] = 0x7f;
|
|
valDer[1] = 0xff;
|
|
valDer[2] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x7fffff, valDer, 3));
|
|
|
|
/* Output 4 bytes min */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0x80;
|
|
valDer[2] = 0x00;
|
|
valDer[3] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x800000, valDer, 4));
|
|
|
|
/* Output 4 bytes max */
|
|
valDer[0] = 0x7f;
|
|
valDer[1] = 0xff;
|
|
valDer[2] = 0xff;
|
|
valDer[3] = 0xff;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x7fffffff, valDer, 4));
|
|
|
|
/* Output 5 bytes min */
|
|
valDer[0] = 0x00;
|
|
valDer[1] = 0x80;
|
|
valDer[2] = 0x00;
|
|
valDer[3] = 0x00;
|
|
valDer[4] = 0x00;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x80000000, valDer, 5));
|
|
|
|
/* Skip "Output 5 bytes max" because of same as "Input 4 bytes max" */
|
|
}
|
|
|
|
/* Extra tests */
|
|
{
|
|
valDer[0] = 0x01;
|
|
EXPECT_TEST(test_GetSetShortInt_once(0x01, valDer, 1));
|
|
}
|
|
|
|
#if !defined(NO_PWDBASED) || defined(WOLFSSL_ASN_EXTRA)
|
|
/* Negative INTEGER values. */
|
|
{
|
|
word32 idx = 0;
|
|
int value;
|
|
|
|
valDer[0] = ASN_INTEGER;
|
|
valDer[1] = 1;
|
|
valDer[2] = 0x80;
|
|
ExpectIntEQ(GetShortInt(valDer, &idx, &value, 3),
|
|
WC_NO_ERR_TRACE(ASN_EXPECT_0_E));
|
|
|
|
idx = 0;
|
|
valDer[0] = ASN_INTEGER;
|
|
valDer[1] = 4;
|
|
valDer[2] = 0xFF;
|
|
valDer[3] = 0xFF;
|
|
valDer[4] = 0xFF;
|
|
valDer[5] = 0xFF;
|
|
ExpectIntEQ(GetShortInt(valDer, &idx, &value, 6),
|
|
WC_NO_ERR_TRACE(ASN_EXPECT_0_E));
|
|
}
|
|
|
|
#if (!defined(HAVE_SELFTEST) && !defined(HAVE_FIPS)) || \
|
|
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))
|
|
/* zero length value. should return ASN_PARSE_E */
|
|
{
|
|
word32 idx = 0;
|
|
int value = 0;
|
|
valDer[0] = ASN_INTEGER;
|
|
valDer[1] = 0x00;
|
|
ExpectIntEQ(GetShortInt(valDer, &idx, &value, 2),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
#endif /* */
|
|
#endif /* !NO_PWDBASED || WOLFSSL_ASN_EXTRA */
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
|
|
int test_wc_IndexSequenceOf(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#ifndef NO_ASN
|
|
const byte int_seq[] = {
|
|
0x30, 0x0A,
|
|
0x02, 0x01, 0x0A,
|
|
0x02, 0x02, 0x00, 0xF0,
|
|
0x02, 0x01, 0x7F,
|
|
};
|
|
const byte bad_seq[] = {
|
|
0xA0, 0x01, 0x01,
|
|
};
|
|
const byte empty_seq[] = {
|
|
0x30, 0x00,
|
|
};
|
|
|
|
const byte * element;
|
|
word32 elementSz;
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(int_seq, sizeof(int_seq), 0U, &element, &elementSz), 0);
|
|
ExpectPtrEq(element, &int_seq[2]);
|
|
ExpectIntEQ(elementSz, 3);
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(int_seq, sizeof(int_seq), 1U, &element, &elementSz), 0);
|
|
ExpectPtrEq(element, &int_seq[5]);
|
|
ExpectIntEQ(elementSz, 4);
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(int_seq, sizeof(int_seq), 2U, &element, &elementSz), 0);
|
|
ExpectPtrEq(element, &int_seq[9]);
|
|
ExpectIntEQ(elementSz, 3);
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(int_seq, sizeof(int_seq), 3U, &element, &elementSz), WC_NO_ERR_TRACE(BAD_INDEX_E));
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(bad_seq, sizeof(bad_seq), 0U, &element, &elementSz), WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
|
|
ExpectIntEQ(wc_IndexSequenceOf(empty_seq, sizeof(empty_seq), 0U, &element, &elementSz), WC_NO_ERR_TRACE(BAD_INDEX_E));
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
|
/* One AttributeTypeAndValue for the directoryName cases below. */
|
|
typedef struct DirTestAttr {
|
|
byte oid; /* Last octet of the 2.5.4.x attribute type OID. */
|
|
byte tag; /* ASN.1 string tag of the value. */
|
|
const byte* val; /* Value content octets. */
|
|
word32 valSz;
|
|
} DirTestAttr;
|
|
|
|
#define DIR_OID_CN 0x03 /* 2.5.4.3 commonName */
|
|
#define DIR_OID_O 0x0a /* 2.5.4.10 organizationName */
|
|
/* OR into the oid field to put the attribute in the same RDN as the one
|
|
* before it, making a multi-valued RDN. The 2.5.4.x attribute types are all
|
|
* well below this bit. */
|
|
#define DIR_JOIN 0x80
|
|
|
|
/* Encode the content octets of an RDNSequence, i.e. what GetCertName()
|
|
* stores in cert->subjectRaw and what DecodeSubtreeGeneralName() stores for
|
|
* a directoryName subtree (the outer SEQUENCE header is stripped in both).
|
|
* Each attribute starts a new RDN unless its oid carries DIR_JOIN, which
|
|
* puts it in the RDN before it. The attributes of a multi-valued RDN are
|
|
* emitted in the order
|
|
* given rather than in DER SET OF order, which is what lets the cases below
|
|
* present the same RDN two ways. Only short form lengths are needed here.
|
|
* Returns the encoded length or -1 if it does not fit. */
|
|
static int dirNameEnc(byte* out, word32 outSz, const DirTestAttr* attrs,
|
|
int cnt)
|
|
{
|
|
word32 idx = 0;
|
|
int i = 0;
|
|
|
|
while (i < cnt) {
|
|
word32 setLenIdx;
|
|
word32 setSz = 0;
|
|
|
|
if ((idx + 2) > outSz) {
|
|
return -1;
|
|
}
|
|
out[idx++] = 0x31; /* SET OF */
|
|
setLenIdx = idx++; /* Length, filled in below. */
|
|
|
|
do {
|
|
/* AttributeTypeAndValue content: the OID TLV plus the value TLV.
|
|
*/
|
|
word32 avaSz = (2 + 3) + (2 + attrs[i].valSz);
|
|
|
|
if ((attrs[i].valSz > 127) || (avaSz > 127) ||
|
|
((idx + 2 + avaSz) > outSz)) {
|
|
return -1;
|
|
}
|
|
|
|
out[idx++] = 0x30; /* SEQUENCE */
|
|
out[idx++] = (byte)avaSz;
|
|
out[idx++] = 0x06; /* OBJECT IDENTIFIER */
|
|
out[idx++] = 0x03;
|
|
out[idx++] = 0x55; /* 2.5.4.x */
|
|
out[idx++] = 0x04;
|
|
out[idx++] = (byte)(attrs[i].oid & (byte)~DIR_JOIN);
|
|
out[idx++] = attrs[i].tag;
|
|
out[idx++] = (byte)attrs[i].valSz;
|
|
XMEMCPY(out + idx, attrs[i].val, attrs[i].valSz);
|
|
idx += attrs[i].valSz;
|
|
|
|
setSz += 2 + avaSz;
|
|
i++;
|
|
} while ((i < cnt) && ((attrs[i].oid & DIR_JOIN) != 0));
|
|
|
|
if (setSz > 127) {
|
|
return -1;
|
|
}
|
|
out[setLenIdx] = (byte)setSz;
|
|
}
|
|
|
|
return (int)idx;
|
|
}
|
|
|
|
/* Encode "Forbid" <cp> "den" as a UTF8String value, i.e. one code point in
|
|
* the middle of a name that is otherwise "Forbidden". A code point RFC 4518
|
|
* Sec. 2.2 maps to nothing drops out and leaves "Forbidden"; any other one
|
|
* stays and makes it a different name. Returns the encoded length. */
|
|
static word32 dirUtf8Probe(byte* out, word32 cp)
|
|
{
|
|
static const byte head[] = { 'F','o','r','b','i','d' };
|
|
static const byte tail[] = { 'd','e','n' };
|
|
word32 idx = (word32)sizeof(head);
|
|
|
|
XMEMCPY(out, head, sizeof(head));
|
|
|
|
if (cp < 0x80U) {
|
|
out[idx++] = (byte)cp;
|
|
}
|
|
else if (cp < 0x800U) {
|
|
out[idx++] = (byte)(0xC0U | (cp >> 6));
|
|
out[idx++] = (byte)(0x80U | (cp & 0x3FU));
|
|
}
|
|
else if (cp < 0x10000U) {
|
|
out[idx++] = (byte)(0xE0U | (cp >> 12));
|
|
out[idx++] = (byte)(0x80U | ((cp >> 6) & 0x3FU));
|
|
out[idx++] = (byte)(0x80U | (cp & 0x3FU));
|
|
}
|
|
else {
|
|
out[idx++] = (byte)(0xF0U | (cp >> 18));
|
|
out[idx++] = (byte)(0x80U | ((cp >> 12) & 0x3FU));
|
|
out[idx++] = (byte)(0x80U | ((cp >> 6) & 0x3FU));
|
|
out[idx++] = (byte)(0x80U | (cp & 0x3FU));
|
|
}
|
|
|
|
XMEMCPY(out + idx, tail, sizeof(tail));
|
|
idx += (word32)sizeof(tail);
|
|
|
|
return idx;
|
|
}
|
|
|
|
/* Encode both names and run them through the directoryName matcher. */
|
|
static int dirMatch(const DirTestAttr* nm, int nmCnt, const DirTestAttr* bs,
|
|
int bsCnt)
|
|
{
|
|
byte nameDer[128];
|
|
byte baseDer[128];
|
|
int nameSz;
|
|
int baseSz;
|
|
|
|
nameSz = dirNameEnc(nameDer, (word32)sizeof(nameDer), nm, nmCnt);
|
|
baseSz = dirNameEnc(baseDer, (word32)sizeof(baseDer), bs, bsCnt);
|
|
if ((nameSz < 0) || (baseSz < 0)) {
|
|
return -1;
|
|
}
|
|
|
|
return wolfssl_local_MatchBaseName(ASN_DIR_TYPE, (const char*)nameDer,
|
|
nameSz, (const char*)baseDer, baseSz);
|
|
}
|
|
#endif /* !NO_CERTS && !NO_ASN && !IGNORE_NAME_CONSTRAINTS */
|
|
|
|
int test_wolfssl_local_MatchBaseName(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
|
/*
|
|
* Tests for DNS type (ASN_DNS_TYPE = 0x02)
|
|
*/
|
|
|
|
/* Positive tests - should match */
|
|
/* Exact match */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com", 10, "domain.com", 10), 1);
|
|
/* Case insensitive match */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"DOMAIN.COM", 10, "domain.com", 10), 1);
|
|
/* Subdomain match (RFC 5280: adding labels to the left) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"sub.domain.com", 14, "domain.com", 10), 1);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"a.b.domain.com", 14, "domain.com", 10), 1);
|
|
/* Leading dot constraint with subdomain (not RFC 5280 compliant for DNS,
|
|
* but kept for backwards compatibility) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"sub.domain.com", 14, ".domain.com", 11), 1);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"a.b.domain.com", 14, ".domain.com", 11), 1);
|
|
/* Trailing-dot normalization: absolute DNS form is equivalent. */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com.", (int)XSTRLEN("domain.com."),
|
|
"domain.com", (int)XSTRLEN("domain.com")), 1);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com", (int)XSTRLEN("domain.com"),
|
|
"domain.com.", (int)XSTRLEN("domain.com.")), 1);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com.", (int)XSTRLEN("domain.com."),
|
|
"domain.com.", (int)XSTRLEN("domain.com.")), 1);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"sub.domain.com.", (int)XSTRLEN("sub.domain.com."),
|
|
".domain.com.", (int)XSTRLEN(".domain.com.")), 1);
|
|
|
|
/* Negative tests - should NOT match */
|
|
/* Bug #3: fakedomain.com should NOT match domain.com (no dot boundary) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"fakedomain.com", 14, "domain.com", 10), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"notdomain.com", 13, "domain.com", 10), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"xexample.com", 12, "example.com", 11), 0);
|
|
/* Bug #3: fakedomain.com should NOT match .domain.com */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"fakedomain.com", 14, ".domain.com", 11), 0);
|
|
/* domain.com should NOT match .domain.com (leading dot requires subdomain) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com", 10, ".domain.com", 11), 0);
|
|
/* Different domain */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"other.com", 9, "domain.com", 10), 0);
|
|
/* Name starting with dot */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
".domain.com", 11, "domain.com", 10), 0);
|
|
/* More than one trailing dot leaves an empty label after normalization. */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com..", (int)XSTRLEN("domain.com.."),
|
|
"domain.com", (int)XSTRLEN("domain.com")), 0);
|
|
|
|
/*
|
|
* Tests for email type (ASN_RFC822_TYPE = 0x01)
|
|
*/
|
|
|
|
/* Positive tests - should match */
|
|
/* Exact email match */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, "user@domain.com", 15), 1);
|
|
/* Email with domain constraint (leading dot) - subdomain present */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@sub.domain.com", 19, ".domain.com", 11), 1);
|
|
/* Email with domain constraint (no leading dot) - exact domain */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, "domain.com", 10), 1);
|
|
|
|
/* Negative tests - should NOT match */
|
|
/* user@domain.com should NOT match .domain.com (subdomain required) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, ".domain.com", 11), 0);
|
|
/* user@sub.domain.com should NOT match domain.com (exact domain only) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@sub.domain.com", 19, "domain.com", 10), 0);
|
|
/* @ at start is invalid */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"@domain.com", 11, ".domain.com", 11), 0);
|
|
/* @ at end is invalid */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@", 5, ".domain.com", 11), 0);
|
|
/* double @ is invalid */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@@domain.com", 16, ".domain.com", 11), 0);
|
|
/* multiple @ is invalid */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain@extra.com", 21, ".domain.com", 11), 0);
|
|
/* No @ in email name */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"userdomain.com", 14, ".domain.com", 11), 0);
|
|
/* Email domain doesn't match constraint */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@other.com", 14, ".domain.com", 11), 0);
|
|
/* Email suffix without dot boundary (fakedomain) */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@fakedomain.com", 19, ".domain.com", 11), 0);
|
|
/* Base constraint with invalid @ position */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, "@domain.com", 11), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, "user@", 5), 0);
|
|
|
|
/* Regression: the scan for '@' in the base must test the length bound
|
|
* before dereferencing. The base is passed with an explicit length and
|
|
* is not required to be NUL terminated, so a bare-domain constraint
|
|
* (no '@' anywhere in it) used to read base[baseSz]. Run the same
|
|
* cases against a heap buffer holding exactly baseSz bytes with no
|
|
* terminator, so that the over-read is a heap overflow that ASAN or
|
|
* valgrind will catch. */
|
|
{
|
|
const char* bases[] = { "domain.com", ".domain.com", "user@domain.com" };
|
|
const int expect[] = { 1, 0, 1 };
|
|
size_t i;
|
|
|
|
for (i = 0; i < XELEM_CNT(bases); i++) {
|
|
char* base = NULL;
|
|
int baseSz = (int)XSTRLEN(bases[i]);
|
|
|
|
ExpectNotNull(base = (char*)XMALLOC((size_t)baseSz, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
if (base != NULL) {
|
|
XMEMCPY(base, bases[i], (size_t)baseSz);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
|
"user@domain.com", 15, base, baseSz), expect[i]);
|
|
XFREE(base, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tests for directory type (ASN_DIR_TYPE = 0x04)
|
|
*
|
|
* A directoryName subtree matches when its RDN sequence is an initial
|
|
* subsequence of the certificate DN (RFC 5280 Sec. 4.2.1.10), with RDNs
|
|
* compared using the Sec. 7.1 name matching rules: the attribute type
|
|
* OID must be identical, but the value is compared by folded code point
|
|
* so that letter case, the ASN.1 string type used and insignificant
|
|
* spacing do not matter. Comparing the DER directly used to let a
|
|
* semantically equal name slip past an excluded subtree.
|
|
*/
|
|
{
|
|
static const byte forbidden[] =
|
|
{ 'F','o','r','b','i','d','d','e','n' };
|
|
static const byte forbiddenUp[] =
|
|
{ 'F','O','R','B','I','D','D','E','N' };
|
|
static const byte forbiddenSp[] =
|
|
{ ' ','F','o','r','b','i','d','d','e','n',' ',' ' };
|
|
static const byte forbid[] = { 'F','o','r','b','i','d' };
|
|
static const byte allowed[] = { 'A','l','l','o','w','e','d' };
|
|
static const byte leaf[] = { 'l','e','a','f' };
|
|
static const byte other[] = { 'o','t','h','e','r' };
|
|
static const byte forBid[] = { 'F','o','r',' ','b','i','d' };
|
|
static const byte forBid2[] = { 'F','o','r',' ',' ','b','i','d' };
|
|
/* "Forbidden" as BMPString (UCS-2) and UniversalString (UCS-4). */
|
|
static const byte forbiddenBmp[] = {
|
|
0,'F', 0,'o', 0,'r', 0,'b', 0,'i', 0,'d', 0,'d', 0,'e', 0,'n'
|
|
};
|
|
static const byte forbiddenUcs[] = {
|
|
0,0,0,'F', 0,0,0,'o', 0,0,0,'r', 0,0,0,'b', 0,0,0,'i',
|
|
0,0,0,'d', 0,0,0,'d', 0,0,0,'e', 0,0,0,'n'
|
|
};
|
|
/* U+00C4 and U+00E4 (A with diaeresis, upper and lower case) in
|
|
* UTF-8 and as a BMPString. */
|
|
static const byte upperAeUtf8[] = { 0xc3, 0x84 };
|
|
static const byte upperAeBmp[] = { 0x00, 0xc4 };
|
|
static const byte lowerAeUtf8[] = { 0xc3, 0xa4 };
|
|
|
|
/* base: O=Forbidden */
|
|
const DirTestAttr bForbidden[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden, sizeof(forbidden) }
|
|
};
|
|
/* base: O=Forbidden, CN=leaf */
|
|
const DirTestAttr bForbiddenLeaf[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden, sizeof(forbidden) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
|
|
/* Exact encoding, subtree is a proper prefix of the DN. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden, sizeof(forbidden) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 1);
|
|
}
|
|
/* Whole DN equals the subtree. */
|
|
ExpectIntEQ(dirMatch(bForbiddenLeaf, 2, bForbiddenLeaf, 2), 1);
|
|
|
|
/* Letter case is ignored. Byte comparison used to miss this and
|
|
* accept the certificate. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbiddenUp,
|
|
sizeof(forbiddenUp) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 1);
|
|
}
|
|
/* A different string type holding the same characters is the same
|
|
* name: PrintableString, BMPString and UniversalString against a
|
|
* UTF8String subtree. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_PRINTABLE_STRING, forbidden,
|
|
sizeof(forbidden) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 1);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_BMPSTRING, forbiddenBmp,
|
|
sizeof(forbiddenBmp) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 1);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UNIVERSALSTRING, forbiddenUcs,
|
|
sizeof(forbiddenUcs) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 1);
|
|
}
|
|
/* Non-ASCII characters compare across string types too. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_BMPSTRING, upperAeBmp, sizeof(upperAeBmp) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, upperAeUtf8,
|
|
sizeof(upperAeUtf8) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 1);
|
|
}
|
|
/* Leading and trailing spaces are insignificant, in either operand.
|
|
* The DN encoding being shorter than the subtree encoding must not
|
|
* short-circuit the comparison. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbiddenSp,
|
|
sizeof(forbiddenSp) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbiddenSp,
|
|
sizeof(forbiddenSp) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 1);
|
|
ExpectIntEQ(dirMatch(bForbidden, 1, bs, 1), 1);
|
|
}
|
|
/* An inner run of spaces collapses to one. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forBid2, sizeof(forBid2) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forBid, sizeof(forBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 1);
|
|
}
|
|
|
|
/* RFC 4518 Sec. 2.2 maps a fixed set of code points to SPACE and
|
|
* another to nothing, so that names differing only in the width of
|
|
* a space or in characters that carry no meaning of their own are
|
|
* the same name. Leaving them unmapped would let a subordinate CA
|
|
* sidestep an excluded subtree with a name that renders the same as
|
|
* the excluded one. */
|
|
{
|
|
/* "For" + NO-BREAK SPACE (U+00A0) + "bid". */
|
|
static const byte forNbspBid[] =
|
|
{ 'F','o','r', 0xc2,0xa0, 'b','i','d' };
|
|
/* "For" + CHARACTER TABULATION + "bid". */
|
|
static const byte forTabBid[] =
|
|
{ 'F','o','r', 0x09, 'b','i','d' };
|
|
/* "For" + IDEOGRAPHIC SPACE (U+3000) + "bid". */
|
|
static const byte forIdeoBid[] =
|
|
{ 'F','o','r', 0xe3,0x80,0x80, 'b','i','d' };
|
|
/* NO-BREAK SPACE either side of "Forbidden". */
|
|
static const byte nbspForbidden[] = {
|
|
0xc2,0xa0, 'F','o','r','b','i','d','d','e','n', 0xc2,0xa0
|
|
};
|
|
/* "For" SPACE SOFT HYPHEN (U+00AD) SPACE "bid": a code point
|
|
* that maps to nothing does not break the run of spaces. */
|
|
static const byte forShyBid[] =
|
|
{ 'F','o','r', ' ', 0xc2,0xad, ' ', 'b','i','d' };
|
|
/* "Forbid" with a ZERO WIDTH SPACE (U+200B) in the middle,
|
|
* which maps to nothing rather than to a space. */
|
|
static const byte forZwspBid[] =
|
|
{ 'F','o','r', 0xe2,0x80,0x8b, 'b','i','d' };
|
|
/* "Forbidden" with VARIATION SELECTOR-1 (U+FE00) in it. */
|
|
static const byte forbidVsDen[] = {
|
|
'F','o','r','b','i','d', 0xef,0xb8,0x80, 'd','e','n'
|
|
};
|
|
/* "For" + the octet 0xa0 + "bid". */
|
|
static const byte forA0Bid[] =
|
|
{ 'F','o','r', 0xa0, 'b','i','d' };
|
|
|
|
/* base: O=For bid */
|
|
const DirTestAttr bForBid[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forBid, sizeof(forBid) }
|
|
};
|
|
/* base: O=Forbid */
|
|
const DirTestAttr bForbid[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbid, sizeof(forbid) }
|
|
};
|
|
|
|
/* Code points that stand in for a space. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forNbspBid,
|
|
sizeof(forNbspBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 1);
|
|
ExpectIntEQ(dirMatch(bForBid, 1, nm, 1), 1);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forTabBid,
|
|
sizeof(forTabBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 1);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forIdeoBid,
|
|
sizeof(forIdeoBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 1);
|
|
}
|
|
/* They are insignificant leading and trailing, as a space is. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, nbspForbidden,
|
|
sizeof(nbspForbidden) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 1);
|
|
}
|
|
/* Code points that map to nothing drop out, leaving the spaces
|
|
* on either side of them one run. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forShyBid,
|
|
sizeof(forShyBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 1);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidVsDen,
|
|
sizeof(forbidVsDen) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 1);
|
|
}
|
|
/* ZERO WIDTH SPACE maps to nothing and not to a space, whatever
|
|
* its name suggests: it joins the two halves rather than
|
|
* separating them. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forZwspBid,
|
|
sizeof(forZwspBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbid, 1), 1);
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 0);
|
|
}
|
|
/* Only the Unicode string types are mapped beyond ASCII. The
|
|
* octet 0xa0 of a T61String is not NO-BREAK SPACE, and in a
|
|
* UTF8String it is not a character at all. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_T61STRING, forA0Bid, sizeof(forA0Bid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 0);
|
|
}
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forA0Bid,
|
|
sizeof(forA0Bid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
|
|
/* EN SPACE, one of the EN QUAD (U+2000) to HAIR SPACE (U+200A)
|
|
* block that Sec. 2.2 gives as a range rather than one by one. */
|
|
{
|
|
static const byte forEnSpBid[] =
|
|
{ 'F','o','r', 0xe2,0x80,0x82, 'b','i','d' };
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forEnSpBid,
|
|
sizeof(forEnSpBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForBid, 1), 1);
|
|
}
|
|
|
|
/* The code points Sec. 2.2 maps to nothing, given there as
|
|
* ranges. Each range is probed just inside and just outside
|
|
* both of its bounds: inside, the code point drops out of the
|
|
* name and what is left is "Forbidden"; outside, it stays and
|
|
* the name is a different one. A range left unmapped would let
|
|
* a certificate carrying one of its code points inside a name
|
|
* pass an excluded subtree. */
|
|
{
|
|
static const struct {
|
|
word32 cp; /* Code point placed inside the name. */
|
|
int drops; /* 1 when Sec. 2.2 maps it to nothing. */
|
|
} probes[] = {
|
|
/* Below CHARACTER TABULATION, and the C0 controls above
|
|
* CARRIAGE RETURN. */
|
|
{ 0x00001, 1 }, { 0x00010, 1 },
|
|
/* DELETE through U+0084, and the C1 controls above NEXT
|
|
* LINE; U+0100 is past both. */
|
|
{ 0x00080, 1 }, { 0x00090, 1 }, { 0x00100, 0 },
|
|
/* The MONGOLIAN FREE VARIATION SELECTORs. */
|
|
{ 0x0180B, 1 }, { 0x01900, 0 },
|
|
/* ZERO WIDTH NON-JOINER through RIGHT-TO-LEFT MARK. */
|
|
{ 0x0200C, 1 }, { 0x02010, 0 },
|
|
/* The bidirectional formatting characters. */
|
|
{ 0x0202A, 1 }, { 0x02030, 0 },
|
|
/* WORD JOINER and the invisible operators. */
|
|
{ 0x02060, 1 }, { 0x02064, 0 },
|
|
/* INHIBIT SYMMETRIC SWAPPING through NOMINAL DIGIT
|
|
* SHAPES. */
|
|
{ 0x0206A, 1 }, { 0x02100, 0 },
|
|
/* The VARIATION SELECTORs. */
|
|
{ 0x0FE00, 1 }, { 0x0FE10, 0 },
|
|
/* The interlinear annotation characters. */
|
|
{ 0x0FFF9, 1 }, { 0x0FFFD, 0 },
|
|
/* The musical symbol combining stems. */
|
|
{ 0x1D173, 1 }, { 0x1D180, 0 },
|
|
/* The deprecated tag characters. */
|
|
{ 0xE0020, 1 }, { 0xE0080, 0 }
|
|
};
|
|
byte probe[32];
|
|
int p;
|
|
|
|
for (p = 0; p < (int)(sizeof(probes) / sizeof(probes[0]));
|
|
p++) {
|
|
DirTestAttr nm[1];
|
|
|
|
nm[0].oid = DIR_OID_O;
|
|
nm[0].tag = ASN_UTF8STRING;
|
|
nm[0].val = probe;
|
|
nm[0].valSz = dirUtf8Probe(probe, probes[p].cp);
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1),
|
|
probes[p].drops);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* A UTF-16 surrogate pair in a BMPString is one code point, and is
|
|
* the same character as the one the UTF-8 spelling holds. */
|
|
{
|
|
/* U+10000 as a surrogate pair and as UTF-8. */
|
|
static const byte astralBmp[] = { 0xd8, 0x00, 0xdc, 0x00 };
|
|
static const byte astralUtf8[] = { 0xf0, 0x90, 0x80, 0x80 };
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_BMPSTRING, astralBmp, sizeof(astralBmp) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, astralUtf8, sizeof(astralUtf8) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 1);
|
|
}
|
|
/* A code unit just above the surrogate block is an ordinary
|
|
* character in both of the wide string types. */
|
|
{
|
|
/* U+E000, the first Private Use character. */
|
|
static const byte puaBmp[] = { 0xe0, 0x00 };
|
|
static const byte puaUcs[] = { 0x00, 0x00, 0xe0, 0x00 };
|
|
const DirTestAttr nmBmp[] = {
|
|
{ DIR_OID_O, ASN_BMPSTRING, puaBmp, sizeof(puaBmp) }
|
|
};
|
|
const DirTestAttr nmUcs[] = {
|
|
{ DIR_OID_O, ASN_UNIVERSALSTRING, puaUcs, sizeof(puaUcs) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nmBmp, 1, bForbidden, 1), 0);
|
|
ExpectIntEQ(dirMatch(nmUcs, 1, bForbidden, 1), 0);
|
|
}
|
|
/* Case folding covers the ASCII letters and leaves everything below
|
|
* them alone. */
|
|
{
|
|
static const byte forbid1[] = { 'F','o','r','b','i','d','1' };
|
|
static const byte forbid1Up[] = { 'F','O','R','B','I','D','1' };
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbid1Up, sizeof(forbid1Up) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbid1, sizeof(forbid1) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 1);
|
|
}
|
|
/* A value that is not a character string type is compared octet for
|
|
* octet: the same octets under a different tag are a different
|
|
* value, and the string rules are not applied to either side. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_OCTET_STRING, forbidden, sizeof(forbidden) }
|
|
};
|
|
const DirTestAttr up[] = {
|
|
{ DIR_OID_O, ASN_OCTET_STRING, forbiddenUp,
|
|
sizeof(forbiddenUp) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 0);
|
|
ExpectIntEQ(dirMatch(bForbidden, 1, nm, 1), 0);
|
|
ExpectIntEQ(dirMatch(nm, 1, nm, 1), 1);
|
|
ExpectIntEQ(dirMatch(nm, 1, up, 1), 0);
|
|
}
|
|
|
|
/* Negative tests - should NOT match */
|
|
|
|
/* Different value. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, allowed, sizeof(allowed) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 0);
|
|
}
|
|
/* A value the subtree value is a prefix of is a different name. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbid, sizeof(forbid) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbidden, 1), 0);
|
|
}
|
|
/* Same value under a different attribute type. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_CN, ASN_UTF8STRING, forbidden, sizeof(forbidden) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bForbidden, 1), 0);
|
|
}
|
|
/* The DN has fewer RDNs than the subtree. */
|
|
ExpectIntEQ(dirMatch(bForbidden, 1, bForbiddenLeaf, 2), 0);
|
|
/* The subtree is not an initial subsequence of the DN. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden, sizeof(forbidden) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, other, sizeof(other) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bForbiddenLeaf, 2), 0);
|
|
}
|
|
/* An inner space is significant, only runs of them collapse. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbid, sizeof(forbid) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forBid, sizeof(forBid) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 0);
|
|
}
|
|
/* Case folding is ASCII only, matching what other implementations
|
|
* canonicalize. U+00C4 and U+00E4 stay distinct. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, lowerAeUtf8,
|
|
sizeof(lowerAeUtf8) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, upperAeUtf8,
|
|
sizeof(upperAeUtf8) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 1, bs, 1), 0);
|
|
}
|
|
|
|
/* An RDN holding several attributes is a set: RFC 5280 Sec. 7.1
|
|
* matches two RDNs when their attributes pair up one for one, in
|
|
* whatever order they were encoded. DER sorts the components of a
|
|
* SET OF by encoding, but the sort key is the encoding while the
|
|
* comparison is deliberately insensitive to it, so equal names can
|
|
* still list their attributes in different orders. */
|
|
{
|
|
/* One RDN: O=Forbidden + CN=leaf. */
|
|
const DirTestAttr mv[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden, sizeof(forbidden) },
|
|
{ DIR_OID_CN | DIR_JOIN, ASN_UTF8STRING, leaf, sizeof(leaf) }
|
|
};
|
|
/* The same RDN with the attributes the other way around. */
|
|
const DirTestAttr mvRev[] = {
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) }
|
|
};
|
|
|
|
/* Order within the RDN does not matter, in either operand. */
|
|
ExpectIntEQ(dirMatch(mv, 2, mvRev, 2), 1);
|
|
ExpectIntEQ(dirMatch(mvRev, 2, mv, 2), 1);
|
|
/* Reordering and the Sec. 7.1 value rules apply together. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_CN, ASN_PRINTABLE_STRING, leaf, sizeof(leaf) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, forbiddenUp,
|
|
sizeof(forbiddenUp) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, mv, 2), 1);
|
|
}
|
|
/* A reordered multi-valued RDN still only matches as a whole
|
|
* RDN of the subtree, with any further DN RDNs ignored. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) },
|
|
{ DIR_OID_CN | DIR_JOIN, ASN_UTF8STRING, leaf,
|
|
sizeof(leaf) },
|
|
{ DIR_OID_CN, ASN_UTF8STRING, other, sizeof(other) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 3, mvRev, 2), 1);
|
|
}
|
|
|
|
/* An attribute of the subtree RDN that the DN RDN does not hold
|
|
* means the RDNs differ, however they are ordered. */
|
|
ExpectIntEQ(dirMatch(bForbidden, 1, mv, 2), 0);
|
|
ExpectIntEQ(dirMatch(mv, 2, bForbidden, 1), 0);
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_CN, ASN_UTF8STRING, other, sizeof(other) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, mv, 2), 0);
|
|
}
|
|
/* The attributes must pair up one for one: a repeated attribute
|
|
* cannot stand in for two different ones. */
|
|
{
|
|
const DirTestAttr twice[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) }
|
|
};
|
|
const DirTestAttr pair[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, allowed,
|
|
sizeof(allowed) }
|
|
};
|
|
ExpectIntEQ(dirMatch(twice, 2, pair, 2), 0);
|
|
ExpectIntEQ(dirMatch(pair, 2, twice, 2), 0);
|
|
ExpectIntEQ(dirMatch(twice, 2, twice, 2), 1);
|
|
}
|
|
}
|
|
|
|
/* Malformed encodings - neither "match" nor "no match" is safe, so
|
|
* the error is returned and the caller rejects the certificate. */
|
|
{
|
|
/* Overlong two octet encoding of "F": it must not decode to a
|
|
* character, or it could impersonate the plain spelling. */
|
|
static const byte overlongF[] =
|
|
{ 0xc1, 0x86, 'o','r','b','i','d','d','e','n' };
|
|
/* Truncated two octet sequence. */
|
|
static const byte truncUtf8[] = { 'F', 0xc3 };
|
|
/* Continuation octet with no lead octet. */
|
|
static const byte loneCont[] = { 0x80, 'F' };
|
|
/* BMPString with an odd number of octets. */
|
|
static const byte oddBmp[] = { 0x00, 'F', 0x00 };
|
|
/* BMPString high surrogate with no low surrogate after it. */
|
|
static const byte loneHiBmp[] = { 0xd8, 0x00, 0x00, 'F' };
|
|
/* BMPString low surrogate with no high surrogate before it. */
|
|
static const byte loneLoBmp[] = { 0xdc, 0x00, 0x00, 'F' };
|
|
/* BMPString high surrogate followed by a code unit that is not
|
|
* a low surrogate. */
|
|
static const byte hiThenPua[] = { 0xd8, 0x00, 0xe0, 0x00 };
|
|
/* UniversalString with a length that is not a multiple of 4. */
|
|
static const byte shortUcs[] = { 0x00, 0x00, 0x00 };
|
|
/* UniversalString code point past the end of Unicode. */
|
|
static const byte bigUcs[] = { 0x00, 0x11, 0x00, 0x00 };
|
|
/* UniversalString holding a surrogate code point, which is not
|
|
* a character. */
|
|
static const byte surrUcs[] = { 0x00, 0x00, 0xd8, 0x00 };
|
|
static const struct {
|
|
byte tag;
|
|
const byte* val;
|
|
word32 valSz;
|
|
} bad[] = {
|
|
{ ASN_UTF8STRING, overlongF, sizeof(overlongF) },
|
|
{ ASN_UTF8STRING, truncUtf8, sizeof(truncUtf8) },
|
|
{ ASN_UTF8STRING, loneCont, sizeof(loneCont) },
|
|
{ ASN_BMPSTRING, oddBmp, sizeof(oddBmp) },
|
|
{ ASN_BMPSTRING, loneHiBmp, sizeof(loneHiBmp) },
|
|
{ ASN_BMPSTRING, loneLoBmp, sizeof(loneLoBmp) },
|
|
{ ASN_BMPSTRING, hiThenPua, sizeof(hiThenPua) },
|
|
{ ASN_UNIVERSALSTRING, shortUcs, sizeof(shortUcs) },
|
|
{ ASN_UNIVERSALSTRING, bigUcs, sizeof(bigUcs) },
|
|
{ ASN_UNIVERSALSTRING, surrUcs, sizeof(surrUcs) }
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < (int)(sizeof(bad) / sizeof(bad[0])); i++) {
|
|
DirTestAttr one[] = {
|
|
{ DIR_OID_O, bad[i].tag, bad[i].val, bad[i].valSz }
|
|
};
|
|
|
|
/* Malformed in the certificate DN. */
|
|
ExpectIntEQ(dirMatch(one, 1, bForbidden, 1),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
/* Malformed in the constraint subtree. */
|
|
ExpectIntEQ(dirMatch(bForbidden, 1, one, 1),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
|
|
/* A malformed value is only decoded once the attribute type
|
|
* matches, so a different OID still answers "no match". */
|
|
{
|
|
const DirTestAttr one[] = {
|
|
{ DIR_OID_CN, ASN_UTF8STRING, truncUtf8,
|
|
sizeof(truncUtf8) }
|
|
};
|
|
ExpectIntEQ(dirMatch(one, 1, bForbidden, 1), 0);
|
|
}
|
|
|
|
/* A malformed attribute inside a multi-valued RDN is reported
|
|
* even though the other attribute of that RDN pairs up. */
|
|
{
|
|
const DirTestAttr nm[] = {
|
|
{ DIR_OID_CN, ASN_UTF8STRING, leaf, sizeof(leaf) },
|
|
{ DIR_OID_O | DIR_JOIN, ASN_UTF8STRING, truncUtf8,
|
|
sizeof(truncUtf8) }
|
|
};
|
|
const DirTestAttr bs[] = {
|
|
{ DIR_OID_O, ASN_UTF8STRING, forbidden,
|
|
sizeof(forbidden) },
|
|
{ DIR_OID_CN | DIR_JOIN, ASN_UTF8STRING, leaf,
|
|
sizeof(leaf) }
|
|
};
|
|
ExpectIntEQ(dirMatch(nm, 2, bs, 2),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Neither operand is a parsable RDNSequence. Reporting "no match" would
|
|
* be fail-open for an excluded subtree and "match" fail-open for a
|
|
* permitted one, so the error is returned instead. */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
|
"CN=test", 7, "CN=test", 7), WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
|
"CN=other", 8, "CN=test", 7), WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
|
|
/*
|
|
* Edge cases and error handling
|
|
*/
|
|
|
|
/* NULL pointers */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
NULL, 10, "domain.com", 10), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com", 10, NULL, 10), 0);
|
|
/* Empty/zero size */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"", 0, "domain.com", 10), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"domain.com", 10, "", 0), 0);
|
|
/* Invalid type */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(0xFF,
|
|
"domain.com", 10, "domain.com", 10), 0);
|
|
/* Name starting with dot */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
".", 1, ".", 1), 0);
|
|
/* Name shorter than base */
|
|
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
|
"a.com", 5, "domain.com", 10), 0);
|
|
|
|
#endif /* !NO_CERTS && !NO_ASN && !IGNORE_NAME_CONSTRAINTS */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
|
/* Convenience wrappers so the cases below read as (name, base) pairs and the
|
|
* string lengths can't drift out of sync with the literals. */
|
|
static int dnsWildPermitted(const char* name, const char* base)
|
|
{
|
|
return wolfssl_local_MatchDnsConstraintWildcard(name, (int)XSTRLEN(name),
|
|
base, (int)XSTRLEN(base), 1);
|
|
}
|
|
static int dnsWildExcluded(const char* name, const char* base)
|
|
{
|
|
return wolfssl_local_MatchDnsConstraintWildcard(name, (int)XSTRLEN(name),
|
|
base, (int)XSTRLEN(base), 0);
|
|
}
|
|
static int uriNC(const char* uri, const char* base)
|
|
{
|
|
return wolfssl_local_MatchUriNameConstraint(uri, (int)XSTRLEN(uri), base,
|
|
(int)XSTRLEN(base));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Tests label-aware matching of a wildcard DNS SAN against a name-constraint
|
|
* subtree. The permitted variant must prove containment (every expansion of
|
|
* the wildcard stays inside the subtree); the excluded variant must detect
|
|
* intersection (some expansion falls inside the subtree). A '*' never crosses
|
|
* a label boundary, so the comparison is by label from the right.
|
|
*/
|
|
int test_wolfssl_local_MatchDnsConstraintWildcard(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
|
/*
|
|
* PERMITTED subtree -- containment. Accept only when EVERY expansion of
|
|
* the wildcard is inside the base subtree.
|
|
*/
|
|
|
|
/* Wildcard is an extra label to the left of the base: always contained. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "example.com"), 1);
|
|
ExpectIntEQ(dnsWildPermitted("*.sub.example.com", "example.com"), 1);
|
|
ExpectIntEQ(dnsWildPermitted("foo*.example.com", "example.com"), 1);
|
|
ExpectIntEQ(dnsWildPermitted("a*b.example.com", "example.com"), 1);
|
|
/* Case-insensitive on the literal tail labels. */
|
|
ExpectIntEQ(dnsWildPermitted("*.EXAMPLE.CoM", "example.com"), 1);
|
|
/* Single-label base; the matched tail "com" is literal. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "com"), 1);
|
|
/* Leading-dot base requires at least one label before it -- the wildcard
|
|
* label satisfies that. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", ".example.com"), 1);
|
|
ExpectIntEQ(dnsWildPermitted("*.sub.example.com", ".example.com"), 1);
|
|
/* Trailing-dot normalization: absolute DNS form is equivalent. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com.", "example.com"), 1);
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "example.com."), 1);
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com.", "example.com."), 1);
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com.", ".example.com."), 1);
|
|
|
|
/* Wildcard lands on a label that must equal the base: NOT provably
|
|
* contained, because the label can expand to something else. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "foo.example.com"), 0);
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com.", "foo.example.com"), 0);
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "foo.example.com."), 0);
|
|
ExpectIntEQ(dnsWildPermitted("ex*.com", "example.com"), 0);
|
|
ExpectIntEQ(dnsWildPermitted("foo.exa*ple.com", "example.com"), 0);
|
|
/* Tail labels do not match the base at all. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", "example.org"), 0);
|
|
ExpectIntEQ(dnsWildPermitted("*.evil.com", "example.com"), 0);
|
|
/* Leading-dot base, but wildcard would have to equal an interior base
|
|
* label. */
|
|
ExpectIntEQ(dnsWildPermitted("*.example.com", ".sub.example.com"), 0);
|
|
/* A bare '*' cannot be proven inside any multi-label-or-single subtree. */
|
|
ExpectIntEQ(dnsWildPermitted("*", "com"), 0);
|
|
|
|
/*
|
|
* EXCLUDED subtree -- intersection. Reject when SOME expansion of the
|
|
* wildcard falls inside the base subtree. A wildcard label is
|
|
* conservatively treated as able to match any single base label.
|
|
*/
|
|
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "foo.example.com"), 1);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com.", "foo.example.com"), 1);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "foo.example.com."), 1);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com.", "foo.example.com."), 1);
|
|
/* Wildcard adds a label on top of the excluded subtree. */
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "example.com"), 1);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "com"), 1);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", ".example.com"), 1);
|
|
/* Wildcard in a non-left label still intersects. */
|
|
ExpectIntEQ(dnsWildExcluded("foo.*.example.com", "bar.example.com"), 1);
|
|
/* Partial-label wildcard: conservatively excluded even though "ex*"
|
|
* cannot actually expand to "foo" (over-rejection, safe). */
|
|
ExpectIntEQ(dnsWildExcluded("ex*.example.com", "foo.example.com"), 1);
|
|
/* A bare '*' can expand to the apex label of a single-label subtree. */
|
|
ExpectIntEQ(dnsWildExcluded("*", "com"), 1);
|
|
|
|
/* No intersection: literal tail labels differ from the base. */
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "foo.other.com"), 0);
|
|
ExpectIntEQ(dnsWildExcluded("*.other.com", "example.com"), 0);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "example.org"), 0);
|
|
/* Leading-dot excluded base needs a label before it; the wildcard SAN has
|
|
* no room for one, so no expansion reaches the proper subtree. */
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", ".foo.example.com"), 0);
|
|
/* Same arity: '*' can expand to the apex label of the base, so the
|
|
* wildcard intersects (*.com can be example.com, which is excluded). */
|
|
ExpectIntEQ(dnsWildExcluded("*.com", "example.com"), 1);
|
|
/* But a base with MORE labels than the name cannot be reached. */
|
|
ExpectIntEQ(dnsWildExcluded("*.com", "a.example.com"), 0);
|
|
|
|
/*
|
|
* Error / degenerate inputs (both flags reject).
|
|
*/
|
|
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard(NULL, 5,
|
|
"com", 3, 1), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard("*.com", 5,
|
|
NULL, 3, 1), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard("*.com", 0,
|
|
"com", 3, 1), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard("*.com", 5,
|
|
"com", 0, 1), 0);
|
|
/* Name beginning with a dot is invalid. */
|
|
ExpectIntEQ(dnsWildPermitted(".x.com", "com"), 0);
|
|
ExpectIntEQ(dnsWildExcluded(".x.com", "com"), 0);
|
|
/* Base that is only dots collapses to nothing. */
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", "."), 0);
|
|
ExpectIntEQ(dnsWildExcluded("*.example.com", ".."), 0);
|
|
/* SAN has an empty interior label ("*..com"), but only the right-most
|
|
* "com" label overlaps the base "com" -- the empty label sits outside the
|
|
* compared suffix, and '*' can expand to any label, so the matcher
|
|
* conservatively reports intersection. */
|
|
ExpectIntEQ(dnsWildExcluded("*..com", "com"), 1);
|
|
|
|
#endif /* !NO_CERTS && !NO_ASN && !IGNORE_NAME_CONSTRAINTS */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* Tests URI name-constraint matching (RFC 5280 4.2.1.10): the constraint
|
|
* applies to the host portion of the URI. A constraint that does NOT begin
|
|
* with a dot is an exact host match; one that begins with a dot matches any
|
|
* host with one or more additional leading labels (the bare host is excluded).
|
|
*/
|
|
int test_wolfssl_local_MatchUriNameConstraint(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
|
/*
|
|
* Exact host match (no leading dot in the constraint).
|
|
*/
|
|
ExpectIntEQ(uriNC("https://host.com/path", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com:8443/x", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("ftp://user@host.com/x", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://HOST.COM", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com?q=1", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com#frag", "host.com"), 1);
|
|
|
|
/* The bug this fix closes: an exact-host constraint must NOT subtree-match
|
|
* a sub-host. */
|
|
ExpectIntEQ(uriNC("https://www.host.com/", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://a.b.host.com", "host.com"), 0);
|
|
/* Suffix that does not respect a label boundary. */
|
|
ExpectIntEQ(uriNC("https://xhost.com", "host.com"), 0);
|
|
/* host.com is a prefix of the URI host but not the whole host. */
|
|
ExpectIntEQ(uriNC("https://host.com.evil.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://other.com", "host.com"), 0);
|
|
|
|
/* Only the initial scheme delimiter can introduce an authority. A URI
|
|
* embedded in an authority-less URI does not supply its host. */
|
|
ExpectIntEQ(uriNC("urn:example:opaque", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("urn:example:https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("foo:/path/https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("urn:example?next=https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("urn:example#https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("sip:victim.example?next=https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("urn:example?next=https://a.host.com/x",
|
|
".host.com"), 0);
|
|
|
|
/* With a real authority, later URLs must not affect host matching. */
|
|
ExpectIntEQ(uriNC("https://other.com/https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://other.com?next=https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://other.com#https://host.com/x",
|
|
"host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://host.com?next=https://other.com/x",
|
|
"host.com"), 1);
|
|
|
|
/* Scheme syntax, not a whitelist:
|
|
* ALPHA *(ALPHA / DIGIT / "+" / "-" / "."). */
|
|
ExpectIntEQ(uriNC("a://host.com", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("Custom+v2-test.1://host.com", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("://host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("1https://host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("ht/tps://host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("ht_tps://host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC(" https://host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https:", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https:/", "host.com"), 0);
|
|
/* Explicit lengths must bound the scheme and separator scans. */
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("abc://host.com", 3,
|
|
"host.com", 8), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("abc://host.com", 4,
|
|
"host.com", 8), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("abc://host.com", 5,
|
|
"host.com", 8), 0);
|
|
|
|
/* A single trailing dot is the absolute-FQDN marker: "host.com." and
|
|
* "host.com" denote the same host and must compare equal, matching the
|
|
* DNS name-constraint path. */
|
|
ExpectIntEQ(uriNC("https://host.com./", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com.:8443/x", "host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://host.com", "host.com."), 1);
|
|
ExpectIntEQ(uriNC("https://host.com./", "host.com."), 1);
|
|
ExpectIntEQ(uriNC("https://v1.addr./", "v1.addr"), 1);
|
|
ExpectIntEQ(uriNC("https://v1.addr/", "v1.addr."), 1);
|
|
/* Only ONE trailing dot is the marker; an empty last label is not. */
|
|
ExpectIntEQ(uriNC("https://host.com../", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://a.host.com../", ".host.com"), 0);
|
|
/* Empty interior labels are not valid DNS host labels. */
|
|
ExpectIntEQ(uriNC("https://a..host.com/", ".host.com"), 0);
|
|
|
|
/*
|
|
* Leading-dot constraint: proper subtree of hosts (apex excluded).
|
|
*/
|
|
ExpectIntEQ(uriNC("https://www.host.com/", ".host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://a.b.host.com", ".host.com"), 1);
|
|
ExpectIntEQ(uriNC("https://www.host.com:443", ".host.com"), 1);
|
|
/* The bare host is NOT in the leading-dot subtree. */
|
|
ExpectIntEQ(uriNC("https://host.com", ".host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://evilhost.com", ".host.com"), 0);
|
|
|
|
/*
|
|
* RFC 5280 URI constraints require a DNS host. IP-literals / IPvFuture
|
|
* hosts in brackets and IPv4address hosts are not DNS reg-names.
|
|
*/
|
|
ExpectIntEQ(uriNC("https://[2001:db8::1]:443/x", "2001:db8::1"), 0);
|
|
ExpectIntEQ(uriNC("https://[2001:db8::1]", "2001:db8::2"), 0);
|
|
ExpectIntEQ(uriNC("https://[v1.addr.]/", "v1.addr"), 0);
|
|
ExpectIntEQ(uriNC("https://[v1.addr.]/", "v1.addr."), 0);
|
|
ExpectIntEQ(uriNC("https://12.31.2.3/", "12.31.2.3"), 0);
|
|
/* An IPv4address host is still not a DNS reg-name when written with the
|
|
* absolute-FQDN trailing dot. */
|
|
ExpectIntEQ(uriNC("https://12.31.2.3./", "12.31.2.3"), 0);
|
|
ExpectIntEQ(uriNC("https://12.31.2.3./", "12.31.2.3."), 0);
|
|
|
|
/*
|
|
* Malformed / degenerate URIs and inputs (reject).
|
|
*/
|
|
ExpectIntEQ(uriNC("no-scheme-host.com", "host.com"), 0);
|
|
ExpectIntEQ(uriNC("https://", "host.com"), 0);
|
|
/* double literal to abide source-check thinking it's a c++ comment */
|
|
ExpectIntEQ(uriNC("https://" "/path", "host.com"), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint(NULL, 10,
|
|
"host.com", 8), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("https://host.com", 16,
|
|
NULL, 8), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("https://host.com", 0,
|
|
"host.com", 8), 0);
|
|
ExpectIntEQ(wolfssl_local_MatchUriNameConstraint("https://host.com", 16,
|
|
"host.com", 0), 0);
|
|
|
|
#endif /* !NO_CERTS && !NO_ASN && !IGNORE_NAME_CONSTRAINTS */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* Testing wc_DecodeRsaPssParams with known DER byte arrays.
|
|
* Exercises both WOLFSSL_ASN_TEMPLATE and non-template paths.
|
|
*/
|
|
int test_wc_DecodeRsaPssParams(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(WC_RSA_PSS) && !defined(NO_RSA) && !defined(NO_ASN)
|
|
enum wc_HashType hash;
|
|
int mgf;
|
|
int saltLen;
|
|
|
|
/* SHA-256 / MGF1-SHA-256 / saltLen=32 */
|
|
static const byte pssParamsSha256[] = {
|
|
0x30, 0x34,
|
|
0xA0, 0x0F,
|
|
0x30, 0x0D,
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
|
0x04, 0x02, 0x01,
|
|
0x05, 0x00,
|
|
0xA1, 0x1C,
|
|
0x30, 0x1A,
|
|
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
|
|
0x01, 0x01, 0x08,
|
|
0x30, 0x0D,
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
|
0x04, 0x02, 0x01,
|
|
0x05, 0x00,
|
|
0xA2, 0x03,
|
|
0x02, 0x01, 0x20,
|
|
};
|
|
|
|
/* Hash-only: SHA-256 hash, defaults for MGF and salt */
|
|
static const byte pssParamsHashOnly[] = {
|
|
0x30, 0x11,
|
|
0xA0, 0x0F,
|
|
0x30, 0x0D,
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
|
0x04, 0x02, 0x01,
|
|
0x05, 0x00,
|
|
};
|
|
|
|
/* Salt-only: default hash/mgf, saltLen=48 */
|
|
static const byte pssParamsSaltOnly[] = {
|
|
0x30, 0x05,
|
|
0xA2, 0x03,
|
|
0x02, 0x01, 0x30,
|
|
};
|
|
|
|
/* NULL tag (05 00) means all defaults */
|
|
static const byte pssParamsNull[] = { 0x05, 0x00 };
|
|
|
|
/* Empty SEQUENCE means all non-default fields omitted => defaults */
|
|
static const byte pssParamsEmptySeq[] = { 0x30, 0x00 };
|
|
|
|
/* --- Test 1: sz=0 => all defaults --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams((const byte*)"", 0,
|
|
&hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 20);
|
|
|
|
/* --- Test 2: NULL tag => all defaults --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(pssParamsNull,
|
|
(word32)sizeof(pssParamsNull), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 20);
|
|
|
|
/* --- Test 3: Empty SEQUENCE => all defaults --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(pssParamsEmptySeq,
|
|
(word32)sizeof(pssParamsEmptySeq), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 20);
|
|
|
|
#ifndef NO_SHA256
|
|
/* --- Test 4: SHA-256 / MGF1-SHA-256 / salt=32 --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(pssParamsSha256,
|
|
(word32)sizeof(pssParamsSha256), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA256);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA256);
|
|
ExpectIntEQ(saltLen, 32);
|
|
|
|
/* --- Test 5: Hash only => SHA-256, default MGF/salt --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(pssParamsHashOnly,
|
|
(word32)sizeof(pssParamsHashOnly), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA256);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 20);
|
|
#endif
|
|
|
|
/* --- Test 6: Salt only => default hash/MGF, salt=48 --- */
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(pssParamsSaltOnly,
|
|
(word32)sizeof(pssParamsSaltOnly), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 48);
|
|
|
|
/* --- Test 7: NULL pointer -> BAD_FUNC_ARG --- */
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(NULL, 10, &hash, &mgf, &saltLen),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
/* --- Test 8: Bad leading tag => ASN_PARSE_E --- */
|
|
{
|
|
static const byte badTag[] = { 0x01, 0x00 };
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(badTag, (word32)sizeof(badTag),
|
|
&hash, &mgf, &saltLen), WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
|
|
/* --- Test 9: trailerField = 1 (trailerFieldBC) => valid in all modes --- */
|
|
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 1 } } = 30 05 a3 03 02 01 01 */
|
|
{
|
|
static const byte trailerValid[] = {
|
|
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x01
|
|
};
|
|
hash = WC_HASH_TYPE_NONE;
|
|
mgf = 0;
|
|
saltLen = 0;
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(trailerValid,
|
|
(word32)sizeof(trailerValid), &hash, &mgf, &saltLen), 0);
|
|
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
|
|
ExpectIntEQ(mgf, WC_MGF1SHA1);
|
|
ExpectIntEQ(saltLen, 20);
|
|
}
|
|
|
|
#ifndef WOLFSSL_NO_ASN_STRICT
|
|
/* --- Test 10: trailerField = 2 => ASN_PARSE_E (strict mode) --- */
|
|
/* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */
|
|
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 2 } } = 30 05 a3 03 02 01 02 */
|
|
{
|
|
static const byte trailerTwo[] = {
|
|
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x02
|
|
};
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(trailerTwo,
|
|
(word32)sizeof(trailerTwo), &hash, &mgf, &saltLen),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
|
|
/* --- Test 11: trailerField = 0 => ASN_PARSE_E (strict mode) --- */
|
|
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 0 } } = 30 05 a3 03 02 01 00 */
|
|
{
|
|
static const byte trailerZero[] = {
|
|
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x00
|
|
};
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(trailerZero,
|
|
(word32)sizeof(trailerZero), &hash, &mgf, &saltLen),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
|
|
/* --- Test 12: trailerField = 256 (multi-byte INTEGER) => ASN_PARSE_E ---
|
|
* Exercises the 2-byte integer branch in GetInteger16Bit (non-template)
|
|
* and the len==2 case of ASN_DATA_TYPE_WORD16 (template path).
|
|
* SEQUENCE { [3] CONSTRUCTED { INTEGER 256 } } = 30 06 a3 04 02 02 01 00
|
|
*/
|
|
{
|
|
static const byte trailerMultiByte[] = {
|
|
0x30, 0x06, 0xa3, 0x04, 0x02, 0x02, 0x01, 0x00
|
|
};
|
|
ExpectIntEQ(wc_DecodeRsaPssParams(trailerMultiByte,
|
|
(word32)sizeof(trailerMultiByte), &hash, &mgf, &saltLen),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
}
|
|
#endif /* !WOLFSSL_NO_ASN_STRICT */
|
|
|
|
#endif /* WC_RSA_PSS && !NO_RSA && !NO_ASN */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that DecodeAltNames rejects a SAN entry whose length exceeds the
|
|
* remaining SEQUENCE length (integer underflow on the length tracker), and
|
|
* that a dNSName SAN carrying an embedded NUL is stored rather than rejected
|
|
* so verification reports a name mismatch instead of a parse error. */
|
|
int test_DecodeAltNames_length_underflow(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_ASN)
|
|
/* Self-signed DER certificate with a well-formed SAN extension.
|
|
* Byte at offset 418 is the SAN SEQUENCE length (0x06). The negative
|
|
* test below copies this cert and shrinks that byte to 0x03 so the
|
|
* DNS entry length exceeds the SEQUENCE bounds. */
|
|
static const unsigned char good_san_cert[] = {
|
|
0x30, 0x82, 0x02, 0xf9, 0x30, 0x82, 0x01, 0xe1, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x02, 0x10, 0x21, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
|
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x0f, 0x31, 0x0d,
|
|
0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x61, 0x61, 0x31,
|
|
0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x32, 0x30, 0x37, 0x31,
|
|
0x37, 0x32, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x32,
|
|
0x31, 0x34, 0x30, 0x36, 0x32, 0x36, 0x35, 0x33, 0x5a, 0x30, 0x0f, 0x31,
|
|
0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x61, 0x61,
|
|
0x61, 0x61, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
|
|
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
|
|
0x0d, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8,
|
|
0x8a, 0x5e, 0x26, 0x23, 0x1b, 0x31, 0xd3, 0x37, 0x1a, 0x70, 0xb2, 0xec,
|
|
0x3f, 0x74, 0xd4, 0xb4, 0x44, 0xe3, 0x7a, 0xa5, 0xc0, 0xf5, 0xaa, 0x97,
|
|
0x26, 0x9a, 0x04, 0xff, 0xda, 0xbe, 0xe5, 0x09, 0x03, 0x98, 0x3d, 0xb5,
|
|
0xbf, 0x01, 0x2c, 0x9a, 0x0a, 0x3a, 0xfb, 0xbc, 0x3c, 0xe7, 0xbe, 0x83,
|
|
0x5c, 0xb3, 0x70, 0xe8, 0x5c, 0xe3, 0xd1, 0x83, 0xc3, 0x94, 0x08, 0xcd,
|
|
0x1a, 0x87, 0xe5, 0xe0, 0x5b, 0x9c, 0x5c, 0x6e, 0xb0, 0x7d, 0xe2, 0x58,
|
|
0x6c, 0xc3, 0xb5, 0xc8, 0x9d, 0x11, 0xf1, 0x5d, 0x96, 0x0d, 0x66, 0x1e,
|
|
0x56, 0x7f, 0x8f, 0x59, 0xa7, 0xa5, 0xe1, 0xc5, 0xe7, 0x81, 0x4c, 0x09,
|
|
0x9d, 0x5e, 0x96, 0xf0, 0x9a, 0xc2, 0x8b, 0x70, 0xd5, 0xab, 0x79, 0x58,
|
|
0x5d, 0xb7, 0x58, 0xaa, 0xfd, 0x75, 0x52, 0xaa, 0x4b, 0xa7, 0x25, 0x68,
|
|
0x76, 0x59, 0x00, 0xee, 0x78, 0x2b, 0x91, 0xc6, 0x59, 0x91, 0x99, 0x38,
|
|
0x3e, 0xa1, 0x76, 0xc3, 0xf5, 0x23, 0x6b, 0xe6, 0x07, 0xea, 0x63, 0x1c,
|
|
0x97, 0x49, 0xef, 0xa0, 0xfe, 0xfd, 0x13, 0xc9, 0xa9, 0x9f, 0xc2, 0x0b,
|
|
0xe6, 0x87, 0x92, 0x5b, 0xcc, 0xf5, 0x42, 0x95, 0x4a, 0xa4, 0x6d, 0x64,
|
|
0xba, 0x7d, 0xce, 0xcb, 0x04, 0xd0, 0xf8, 0xe7, 0xe3, 0xda, 0x75, 0x60,
|
|
0xd3, 0x8b, 0x6a, 0x64, 0xfc, 0x78, 0x56, 0x21, 0x69, 0x5a, 0xe8, 0xa7,
|
|
0x8f, 0xfb, 0x8f, 0x82, 0xe3, 0xae, 0x36, 0xa2, 0x93, 0x66, 0x92, 0xcb,
|
|
0x82, 0xa3, 0xbe, 0x84, 0x00, 0x86, 0xdc, 0x7e, 0x6d, 0x53, 0x77, 0x84,
|
|
0x17, 0xb9, 0x55, 0x43, 0x0d, 0xf1, 0x16, 0x1f, 0xd5, 0x43, 0x75, 0x99,
|
|
0x66, 0x19, 0x52, 0xd0, 0xac, 0x5f, 0x74, 0xad, 0xb2, 0x90, 0x15, 0x50,
|
|
0x04, 0x74, 0x43, 0xdf, 0x6c, 0x35, 0xd0, 0xfd, 0x32, 0x37, 0xb3, 0x8d,
|
|
0xf5, 0xe5, 0x09, 0x02, 0x01, 0x03, 0xa3, 0x61, 0x30, 0x5f, 0x30, 0x0c,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
|
|
/* SAN extension: correct SEQUENCE length 0x06 */
|
|
0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x08, 0x30, 0x06, 0x82,
|
|
0x04, 0x61, 0x2a, 0x62, 0x2a, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
|
|
0x04, 0x16, 0x04, 0x14, 0x92, 0x6a, 0x1e, 0x52, 0x3a, 0x1a, 0x57, 0x9f,
|
|
0xc9, 0x82, 0x9a, 0xce, 0xc8, 0xc0, 0xa9, 0x51, 0x9d, 0x2f, 0xc7, 0x72,
|
|
0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
|
|
0x14, 0x6b, 0xf9, 0xa4, 0x2d, 0xa5, 0xe9, 0x39, 0x89, 0xa8, 0x24, 0x58,
|
|
0x79, 0x87, 0x11, 0xfc, 0x6f, 0x07, 0x91, 0xef, 0xa6, 0x30, 0x0d, 0x06,
|
|
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
|
|
0x03, 0x82, 0x01, 0x01, 0x00, 0x3f, 0xd5, 0x37, 0x2f, 0xc7, 0xf8, 0x8b,
|
|
0x39, 0x1c, 0xe3, 0xdf, 0x77, 0xee, 0xc6, 0x4b, 0x5f, 0x84, 0xcf, 0xfa,
|
|
0x33, 0x2c, 0xb2, 0xb5, 0x4b, 0x09, 0xee, 0x56, 0xc0, 0xf2, 0xf0, 0xeb,
|
|
0xad, 0x1c, 0x02, 0xef, 0xae, 0x09, 0x53, 0xc0, 0x06, 0xad, 0x4e, 0xfd,
|
|
0x3e, 0x8c, 0x13, 0xb3, 0xbf, 0x80, 0x05, 0x36, 0xb5, 0x3f, 0x2b, 0xc7,
|
|
0x60, 0x53, 0x14, 0xbf, 0x33, 0x63, 0x47, 0xc3, 0xc6, 0x28, 0xda, 0x10,
|
|
0x12, 0xe2, 0xc4, 0xeb, 0xc5, 0x64, 0x66, 0xc0, 0xcc, 0x6b, 0x84, 0xda,
|
|
0x0c, 0xe9, 0xf6, 0xe3, 0xf8, 0x8e, 0x3d, 0x95, 0x5f, 0xba, 0x9f, 0xe1,
|
|
0xc7, 0xed, 0x6e, 0x97, 0xcc, 0xbd, 0x7d, 0xe5, 0x4e, 0xab, 0xbc, 0x1b,
|
|
0xf1, 0x3a, 0x09, 0x33, 0x09, 0xe1, 0xcc, 0xec, 0x21, 0x16, 0x8e, 0xb1,
|
|
0x74, 0x9e, 0xc8, 0x13, 0x7c, 0xdf, 0x07, 0xaa, 0xeb, 0x70, 0xd7, 0x91,
|
|
0x5c, 0xc4, 0xef, 0x83, 0x88, 0xc3, 0xe4, 0x97, 0xfa, 0xe4, 0xdf, 0xd7,
|
|
0x0d, 0xff, 0xba, 0x78, 0x22, 0xfc, 0x3f, 0xdc, 0xd8, 0x02, 0x8d, 0x93,
|
|
0x57, 0xf9, 0x9e, 0x39, 0x3a, 0x77, 0x00, 0xd9, 0x19, 0xaa, 0x68, 0xa1,
|
|
0xe6, 0x9e, 0x13, 0xeb, 0x37, 0x16, 0xf5, 0x77, 0xa4, 0x0b, 0x40, 0x04,
|
|
0xd3, 0xa5, 0x49, 0x78, 0x35, 0xfa, 0x3b, 0xf6, 0x02, 0xab, 0x85, 0xee,
|
|
0xcb, 0x9b, 0x62, 0xda, 0x05, 0x00, 0x22, 0x2f, 0xf8, 0xbd, 0x0b, 0xe5,
|
|
0x2c, 0xb2, 0x53, 0x78, 0x0a, 0xcb, 0x69, 0xc0, 0xb6, 0x9f, 0x96, 0xff,
|
|
0x58, 0x22, 0x70, 0x9c, 0x01, 0x2e, 0x56, 0x60, 0x5d, 0x37, 0xe3, 0x40,
|
|
0x25, 0xc9, 0x90, 0xc8, 0x0f, 0x41, 0x68, 0xb4, 0xfd, 0x10, 0xe2, 0x09,
|
|
0x99, 0x08, 0x5d, 0x7b, 0xc9, 0xe3, 0x29, 0xd4, 0x5a, 0xcf, 0xc9, 0x34,
|
|
0x55, 0xa1, 0x40, 0x44, 0xd6, 0x88, 0x16, 0xbb, 0xdd
|
|
};
|
|
|
|
/* Offset of the SAN SEQUENCE length byte inside good_san_cert. */
|
|
#define SAN_SEQ_LEN_OFFSET 418
|
|
|
|
DecodedCert cert;
|
|
unsigned char bad_san_cert[sizeof(good_san_cert)];
|
|
|
|
/* Control: the original cert with correct SAN SEQUENCE length should
|
|
* parse successfully (signature won't verify, but NO_VERIFY skips that). */
|
|
wc_InitDecodedCert(&cert, good_san_cert, (word32)sizeof(good_san_cert),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* Build a malformed variant: shrink the SAN SEQUENCE length from 6 to 3
|
|
* so the DNS entry length (4) exceeds the SEQUENCE bounds. Without a
|
|
* bounds check DecodeAltNames would underflow the length tracker. */
|
|
XMEMCPY(bad_san_cert, good_san_cert, sizeof(good_san_cert));
|
|
bad_san_cert[SAN_SEQ_LEN_OFFSET] = 0x03;
|
|
|
|
wc_InitDecodedCert(&cert, bad_san_cert, (word32)sizeof(bad_san_cert),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* An embedded NUL in a dNSName SAN is an invalid presented identifier
|
|
* (RFC 6125 Sec. 6.3 / RFC 9525 Sec. 6.3), not a malformed certificate.
|
|
* Set the third byte of the 4-byte dNSName ("a*b*") to NUL, giving
|
|
* "a*\0*". The certificate must still parse: the entry is stored with
|
|
* its embedded NUL intact (length 4, not truncated) so that hostname
|
|
* verification reports DOMAIN_NAME_MISMATCH rather than the parser
|
|
* aborting with ASN_PARSE_E (regression from curl test 311). */
|
|
XMEMCPY(bad_san_cert, good_san_cert, sizeof(good_san_cert));
|
|
bad_san_cert[SAN_SEQ_LEN_OFFSET + 5] = 0x00;
|
|
|
|
wc_InitDecodedCert(&cert, bad_san_cert, (word32)sizeof(bad_san_cert),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectNotNull(cert.altNames);
|
|
if (cert.altNames != NULL) {
|
|
ExpectIntEQ(cert.altNames->type, ASN_DNS_TYPE);
|
|
ExpectIntEQ(cert.altNames->len, 4);
|
|
/* Embedded NUL preserved at offset 2: stored, not truncated. */
|
|
ExpectNotNull(cert.altNames->name);
|
|
if (cert.altNames->name != NULL) {
|
|
ExpectIntEQ(cert.altNames->name[2], 0x00);
|
|
}
|
|
}
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
#endif /* !NO_CERTS && !NO_RSA && !NO_ASN */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* A certificate must not carry two certificatePolicies extensions
|
|
* (non-repeatable per RFC 5280 4.2). DecodeCertExtensions calls
|
|
* DecodeExtensionType once per extension; a second certificatePolicies
|
|
* extension must be rejected (ASN_OBJECT_ID_E) rather than silently
|
|
* overwriting the first - which happened in WOLFSSL_CERT_EXT builds without
|
|
* WOLFSSL_SEP before the duplicate guard was extended to cover them. */
|
|
/* RFC 5280 4.2.1.13: a DistributionPointName fullName is GeneralNames, a
|
|
* SEQUENCE OF GeneralName, so more than one URI may appear. wolfSSL keeps only
|
|
* the first, and the template describes only that one - the remaining names
|
|
* are left for the caller and must not be mistaken for a container that was
|
|
* not used up. */
|
|
int test_DecodeCertExtensions_crldp_multiple_uri(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
|
|
!defined(NO_CERTS) && !defined(NO_ASN)
|
|
/* CRLDistributionPoints with one DistributionPoint whose fullName holds
|
|
* two URIs: "http://a" and "http://b". */
|
|
static const byte crldp2[] = {
|
|
0x30, 0x1a, /* CRLDistributionPoints */
|
|
0x30, 0x18, /* DistributionPoint */
|
|
0xa0, 0x16, /* distributionPoint [0] */
|
|
0xa0, 0x14, /* fullName [0] */
|
|
0x86, 0x08, 'h', 't', 't', 'p', ':', '/', '/', 'a',
|
|
0x86, 0x08, 'h', 't', 't', 'p', ':', '/', '/', 'b'
|
|
};
|
|
DecodedCert cert;
|
|
int isUnknown = 0;
|
|
|
|
wc_InitDecodedCert(&cert, crldp2, (word32)sizeof(crldp2), NULL);
|
|
|
|
ExpectIntEQ(DecodeExtensionType(crldp2, (word32)sizeof(crldp2),
|
|
CRL_DIST_OID, 0, &cert, &isUnknown), 0);
|
|
/* The first URI is the one kept. */
|
|
ExpectIntEQ(cert.extCrlInfoSz, 8);
|
|
ExpectNotNull(cert.extCrlInfo);
|
|
if (cert.extCrlInfo != NULL && cert.extCrlInfoSz == 8) {
|
|
ExpectIntEQ(XMEMCMP(cert.extCrlInfo, "http://a", 8), 0);
|
|
}
|
|
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_DecodeCertExtensions_dup_certpol(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
|
|
!defined(NO_CERTS) && !defined(NO_ASN)
|
|
/* Minimal certificatePolicies extnValue: SEQUENCE OF PolicyInformation
|
|
* with one policyIdentifier OID 1.2.3.4 (encoded 2A 03 04). */
|
|
static const byte policy[] = {
|
|
0x30, 0x07, /* certificatePolicies SEQUENCE */
|
|
0x30, 0x05, /* PolicyInformation SEQUENCE */
|
|
0x06, 0x03, 0x2A, 0x03, 0x04 /* policyIdentifier OID 1.2.3.4 */
|
|
};
|
|
DecodedCert cert;
|
|
int isUnknown = 0;
|
|
|
|
/* DecodeExtensionType only needs an initialized DecodedCert for its
|
|
* bit-fields and policy storage; the source buffer is never parsed here,
|
|
* so any non-NULL pointer/size suffices. */
|
|
wc_InitDecodedCert(&cert, policy, (word32)sizeof(policy), NULL);
|
|
|
|
/* First certificatePolicies extension: accepted. */
|
|
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
|
|
CERT_POLICY_OID, 0, &cert, &isUnknown), 0);
|
|
/* Duplicate certificatePolicies extension: rejected as non-repeatable. */
|
|
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
|
|
CERT_POLICY_OID, 0, &cert, &isUnknown),
|
|
WC_NO_ERR_TRACE(ASN_OBJECT_ID_E));
|
|
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* RFC 5280 4.2.1.4 defines certificatePolicies as SEQUENCE SIZE (1..MAX) OF
|
|
* PolicyInformation, so an empty SEQUENCE must be rejected instead of being
|
|
* accepted as zero policies. */
|
|
int test_DecodeCertExtensions_empty_certpol(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
|
|
!defined(NO_CERTS) && !defined(NO_ASN)
|
|
/* certificatePolicies extnValue carrying no PolicyInformation. */
|
|
static const byte emptyPolicy[] = {
|
|
0x30, 0x00 /* certificatePolicies SEQUENCE */
|
|
};
|
|
DecodedCert cert;
|
|
int isUnknown = 0;
|
|
|
|
wc_InitDecodedCert(&cert, emptyPolicy, (word32)sizeof(emptyPolicy), NULL);
|
|
|
|
ExpectIntEQ(DecodeExtensionType(emptyPolicy, (word32)sizeof(emptyPolicy),
|
|
CERT_POLICY_OID, 0, &cert, &isUnknown),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Trailing bytes after the last PolicyInformation must be rejected rather than
|
|
* skipped. */
|
|
int test_DecodeCertExtensions_certpol_trailing_junk(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
|
|
!defined(NO_CERTS) && !defined(NO_ASN)
|
|
/* One valid PolicyInformation followed by two bytes that are not one. */
|
|
static const byte trailingJunk[] = {
|
|
0x30, 0x09, /* certificatePolicies SEQUENCE */
|
|
0x30, 0x05, /* PolicyInformation SEQUENCE */
|
|
0x06, 0x03, 0x2A, 0x03, 0x04,/* policyIdentifier OID 1.2.3.4 */
|
|
0x00, 0x00 /* trailing junk */
|
|
};
|
|
DecodedCert cert;
|
|
int isUnknown = 0;
|
|
|
|
wc_InitDecodedCert(&cert, trailingJunk, (word32)sizeof(trailingJunk), NULL);
|
|
|
|
ExpectIntEQ(DecodeExtensionType(trailingJunk, (word32)sizeof(trailingJunk),
|
|
CERT_POLICY_OID, 0, &cert, &isUnknown),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* An empty certificatePolicies SEQUENCE followed by extra bytes: the
|
|
* non-template decoder reads a PolicyInformation before testing the loop
|
|
* condition, so it parses those bytes past the SEQUENCE end and returns 0. */
|
|
int test_DecodeCertExtensions_empty_certpol_trailing(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
|
|
!defined(NO_CERTS) && !defined(NO_ASN)
|
|
static const byte emptyThenPolicy[] = {
|
|
0x30, 0x00, /* certificatePolicies SEQUENCE */
|
|
0x30, 0x05, /* bytes after the SEQUENCE */
|
|
0x06, 0x03, 0x2A, 0x03, 0x04 /* OID 1.2.3.4 */
|
|
};
|
|
DecodedCert cert;
|
|
int isUnknown = 0;
|
|
|
|
wc_InitDecodedCert(&cert, emptyThenPolicy, (word32)sizeof(emptyThenPolicy),
|
|
NULL);
|
|
|
|
ExpectIntEQ(DecodeExtensionType(emptyThenPolicy,
|
|
(word32)sizeof(emptyThenPolicy), CERT_POLICY_OID, 0, &cert, &isUnknown),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
#ifdef WOLFSSL_CERT_EXT
|
|
ExpectIntEQ(cert.extCertPoliciesNb, 0);
|
|
#endif
|
|
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* A constructed ASN.1 item must be exactly consumed by the items parsed out of
|
|
* it. GetASN_Items() used to only enforce that for containers still open when
|
|
* the template ran out, so a container the template walked into and back out of
|
|
* mid-way could declare a length longer than its contents and have the excess
|
|
* silently ignored.
|
|
*
|
|
* For a certificate that means TBSCertificate.validity can claim a length that
|
|
* runs past notBefore/notAfter and swallows subject, subjectPublicKeyInfo and
|
|
* the start of extensions. wolfSSL resumed parsing right after notAfter and
|
|
* accepted the certificate, while a strict parser rejects it and a lax one may
|
|
* resume after the declared end of validity and read a completely different
|
|
* subjectPublicKeyInfo. That disagreement is exploitable: a peer holding only
|
|
* the key at the real SPKI offset can satisfy an application's public-key pin
|
|
* for an unrelated key embedded in an extension.
|
|
*
|
|
* The two DERs below differ in exactly one byte: the length octet of the
|
|
* validity SEQUENCE, 0x1e (30, the correct length) versus 0x59 (89). */
|
|
int test_ParseCert_validity_length_overrun(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && defined(HAVE_ED25519) && \
|
|
defined(HAVE_ED25519_VERIFY)
|
|
/* Ed25519 certificate, empty issuer and subject, one unknown extension
|
|
* whose payload happens to be a second, well-formed SPKI. Well-formed:
|
|
* validity SEQUENCE at offset 43 has length 30 and holds exactly the two
|
|
* UTCTIMEs at offsets 45 and 60. */
|
|
static const byte validCert[] = {
|
|
0x30, 0x82, 0x01, 0x19, 0x30, 0x81, 0xcc, 0xa0, 0x03, 0x02, 0x01, 0x02,
|
|
0x02, 0x14, 0x3c, 0x4a, 0xc9, 0xfc, 0x05, 0xa5, 0x6c, 0xaa, 0x52, 0x8a,
|
|
0x71, 0xcb, 0xfc, 0xd4, 0xd1, 0x6e, 0x29, 0x8d, 0x6f, 0x01, 0x30, 0x05,
|
|
0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x00,
|
|
/* validity SEQUENCE, correct length 30 */
|
|
0x30, 0x1e, 0x17, 0x0d, 0x32,
|
|
0x36, 0x30, 0x39, 0x30, 0x32, 0x30, 0x34, 0x35, 0x34, 0x32, 0x36, 0x5a,
|
|
0x17, 0x0d, 0x32, 0x36, 0x31, 0x30, 0x30, 0x32, 0x30, 0x34, 0x35, 0x34,
|
|
0x32, 0x36, 0x5a, 0x30, 0x00, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b,
|
|
0x65, 0x70, 0x03, 0x21, 0x00, 0x5e, 0x1b, 0x44, 0xb7, 0xe3, 0x7b, 0x3d,
|
|
0xe7, 0x24, 0x66, 0x20, 0xaf, 0x31, 0x66, 0x61, 0xaf, 0x52, 0x68, 0xa2,
|
|
0x62, 0xf4, 0x47, 0xe5, 0x93, 0x1c, 0x3e, 0xae, 0xab, 0xbc, 0x71, 0xca,
|
|
0xc2, 0xa3, 0x58, 0x30, 0x56, 0x30, 0x35, 0x06, 0x03, 0x2a, 0x03, 0x04,
|
|
0x04, 0x2e, 0x30, 0x00, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
|
|
0x70, 0x03, 0x21, 0x00, 0xf3, 0xf9, 0x4d, 0x74, 0x9e, 0xd9, 0x61, 0xed,
|
|
0xfd, 0xb7, 0x9b, 0x6c, 0xff, 0x1e, 0x1c, 0xf5, 0xeb, 0x1b, 0x72, 0xcd,
|
|
0xc5, 0x8c, 0xfc, 0x4e, 0x71, 0xcd, 0x82, 0x9c, 0x13, 0x16, 0xc4, 0xfb,
|
|
0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7a,
|
|
0x6a, 0xa2, 0xfd, 0x2e, 0xb6, 0x62, 0x22, 0x98, 0x18, 0x0b, 0x2d, 0x17,
|
|
0xe1, 0xf3, 0x6b, 0x86, 0x01, 0x50, 0xb1, 0x30, 0x05, 0x06, 0x03, 0x2b,
|
|
0x65, 0x70, 0x03, 0x41, 0x00, 0x0b, 0x53, 0x43, 0x87, 0x19, 0xc2, 0x2f,
|
|
0x7d, 0x3c, 0x32, 0x8a, 0x7f, 0xfe, 0xbb, 0xd7, 0x2c, 0x27, 0xd8, 0x59,
|
|
0x5b, 0x47, 0x3e, 0x5d, 0xd1, 0xc9, 0x63, 0x9b, 0x83, 0x74, 0x24, 0x75,
|
|
0x3b, 0xdd, 0x8a, 0xe1, 0x59, 0xe8, 0xcd, 0xff, 0xd0, 0x09, 0xee, 0xc8,
|
|
0x4c, 0xe2, 0x7c, 0x69, 0x49, 0xc2, 0xb3, 0xb2, 0x60, 0x7f, 0x9c, 0x6b,
|
|
0x0e, 0x0c, 0x97, 0x64, 0xd7, 0x6e, 0x9b, 0x4e, 0x00
|
|
};
|
|
/* Byte-for-byte identical except offset 44: the validity SEQUENCE declares
|
|
* length 89, so it runs to offset 134 and covers subject (75),
|
|
* subjectPublicKeyInfo (77) and the head of the extensions (121). */
|
|
static const byte overrunCert[] = {
|
|
0x30, 0x82, 0x01, 0x19, 0x30, 0x81, 0xcc, 0xa0, 0x03, 0x02, 0x01, 0x02,
|
|
0x02, 0x14, 0x3c, 0x4a, 0xc9, 0xfc, 0x05, 0xa5, 0x6c, 0xaa, 0x52, 0x8a,
|
|
0x71, 0xcb, 0xfc, 0xd4, 0xd1, 0x6e, 0x29, 0x8d, 0x6f, 0x01, 0x30, 0x05,
|
|
0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x00,
|
|
/* validity SEQUENCE, overrunning length 89 */
|
|
0x30, 0x59, 0x17, 0x0d, 0x32,
|
|
0x36, 0x30, 0x39, 0x30, 0x32, 0x30, 0x34, 0x35, 0x34, 0x32, 0x36, 0x5a,
|
|
0x17, 0x0d, 0x32, 0x36, 0x31, 0x30, 0x30, 0x32, 0x30, 0x34, 0x35, 0x34,
|
|
0x32, 0x36, 0x5a, 0x30, 0x00, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b,
|
|
0x65, 0x70, 0x03, 0x21, 0x00, 0x5e, 0x1b, 0x44, 0xb7, 0xe3, 0x7b, 0x3d,
|
|
0xe7, 0x24, 0x66, 0x20, 0xaf, 0x31, 0x66, 0x61, 0xaf, 0x52, 0x68, 0xa2,
|
|
0x62, 0xf4, 0x47, 0xe5, 0x93, 0x1c, 0x3e, 0xae, 0xab, 0xbc, 0x71, 0xca,
|
|
0xc2, 0xa3, 0x58, 0x30, 0x56, 0x30, 0x35, 0x06, 0x03, 0x2a, 0x03, 0x04,
|
|
0x04, 0x2e, 0x30, 0x00, 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
|
|
0x70, 0x03, 0x21, 0x00, 0xf3, 0xf9, 0x4d, 0x74, 0x9e, 0xd9, 0x61, 0xed,
|
|
0xfd, 0xb7, 0x9b, 0x6c, 0xff, 0x1e, 0x1c, 0xf5, 0xeb, 0x1b, 0x72, 0xcd,
|
|
0xc5, 0x8c, 0xfc, 0x4e, 0x71, 0xcd, 0x82, 0x9c, 0x13, 0x16, 0xc4, 0xfb,
|
|
0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7a,
|
|
0x6a, 0xa2, 0xfd, 0x2e, 0xb6, 0x62, 0x22, 0x98, 0x18, 0x0b, 0x2d, 0x17,
|
|
0xe1, 0xf3, 0x6b, 0x86, 0x01, 0x50, 0xb1, 0x30, 0x05, 0x06, 0x03, 0x2b,
|
|
0x65, 0x70, 0x03, 0x41, 0x00, 0x0b, 0x53, 0x43, 0x87, 0x19, 0xc2, 0x2f,
|
|
0x7d, 0x3c, 0x32, 0x8a, 0x7f, 0xfe, 0xbb, 0xd7, 0x2c, 0x27, 0xd8, 0x59,
|
|
0x5b, 0x47, 0x3e, 0x5d, 0xd1, 0xc9, 0x63, 0x9b, 0x83, 0x74, 0x24, 0x75,
|
|
0x3b, 0xdd, 0x8a, 0xe1, 0x59, 0xe8, 0xcd, 0xff, 0xd0, 0x09, 0xee, 0xc8,
|
|
0x4c, 0xe2, 0x7c, 0x69, 0x49, 0xc2, 0xb3, 0xb2, 0x60, 0x7f, 0x9c, 0x6b,
|
|
0x0e, 0x0c, 0x97, 0x64, 0xd7, 0x6e, 0x9b, 0x4e, 0x00
|
|
};
|
|
DecodedCert cert;
|
|
|
|
/* The two encodings differ in the one length octet and nothing else. */
|
|
ExpectIntEQ(sizeof(validCert), sizeof(overrunCert));
|
|
ExpectIntEQ(validCert[44], 0x1e);
|
|
ExpectIntEQ(overrunCert[44], 0x59);
|
|
ExpectIntEQ(XMEMCMP(validCert, overrunCert, 44), 0);
|
|
ExpectIntEQ(XMEMCMP(validCert + 45, overrunCert + 45,
|
|
sizeof(validCert) - 45), 0);
|
|
|
|
/* Sanity check: the well-formed encoding parses. */
|
|
wc_InitDecodedCert(&cert, validCert, (word32)sizeof(validCert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* The overrunning validity length must be rejected. */
|
|
wc_InitDecodedCert(&cert, overrunCert, (word32)sizeof(overrunCert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* wolfSSL stores at most MAX_CERTPOL_NB certificate policies. Before the fix
|
|
* the decoder stopped at that limit and returned success, so a critical
|
|
* certificatePolicies extension carrying MAX_CERTPOL_NB+1 unique policies was
|
|
* accepted with its extra policies left uninterpreted (issue 10628). RFC 5280
|
|
* 4.2 requires rejecting a critical extension that cannot be fully processed:
|
|
* it is now reported as an unsupported critical extension (ASN_CRIT_EXT_E,
|
|
* unless WOLFSSL_NO_ASN_STRICT). A non-critical over-limit extension keeps the
|
|
* first MAX_CERTPOL_NB policies and is still accepted, as is an at-limit one. */
|
|
#if defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && !defined(NO_ASN)
|
|
/* Build a certificatePolicies extnValue with n PolicyInformation entries,
|
|
* each SEQUENCE { policyIdentifier OID 1.2.3.4.(k+1) }. The outer SEQUENCE
|
|
* length is written in short form, or long form with a single length octet
|
|
* once the content reaches 0x80, so the result is valid DER for content up to
|
|
* 255 bytes (n <= 31) - ample for the handful of policies used here. Returns
|
|
* the encoded length. out must hold 3 + 8*n bytes. n <= 127 keeps the OID arc
|
|
* single-byte. */
|
|
static word32 test_certpol_build(byte* out, int n)
|
|
{
|
|
word32 content = (word32)(8 * n);
|
|
word32 o;
|
|
int k;
|
|
|
|
out[0] = 0x30; /* certificatePolicies SEQUENCE OF */
|
|
if (content < 0x80U) {
|
|
out[1] = (byte)content;
|
|
o = 2;
|
|
}
|
|
else {
|
|
out[1] = 0x81U; /* long form, one length octet */
|
|
out[2] = (byte)content;
|
|
o = 3;
|
|
}
|
|
for (k = 0; k < n; k++) {
|
|
out[o++] = 0x30; out[o++] = 0x06; /* PolicyInformation SEQ */
|
|
out[o++] = 0x06; out[o++] = 0x04; /* policyIdentifier OID */
|
|
out[o++] = 0x2A; out[o++] = 0x03; /* 1.2.3 */
|
|
out[o++] = 0x04; out[o++] = (byte)(k + 1); /* .4.(k+1) */
|
|
}
|
|
return o;
|
|
}
|
|
#endif
|
|
|
|
int test_DecodeCertPolicy_tooMany(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && !defined(NO_ASN)
|
|
byte ext[3 + 8 * (MAX_CERTPOL_NB + 1)];
|
|
word32 len;
|
|
DecodedCert cert;
|
|
int isUnknown;
|
|
|
|
/* Exactly MAX_CERTPOL_NB policies: fully processed, accepted. */
|
|
len = test_certpol_build(ext, MAX_CERTPOL_NB);
|
|
isUnknown = 0;
|
|
wc_InitDecodedCert(&cert, ext, len, NULL);
|
|
ExpectIntEQ(DecodeExtensionType(ext, len, CERT_POLICY_OID, 1, &cert,
|
|
&isUnknown), 0);
|
|
ExpectIntEQ(cert.extCertPoliciesNb, MAX_CERTPOL_NB);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
#ifndef WOLFSSL_NO_ASN_STRICT
|
|
/* One more than can be stored, critical: cannot be fully processed, so it
|
|
* is rejected as an unsupported critical extension rather than accepted
|
|
* with the extra policy left uninterpreted. */
|
|
len = test_certpol_build(ext, MAX_CERTPOL_NB + 1);
|
|
isUnknown = 0;
|
|
wc_InitDecodedCert(&cert, ext, len, NULL);
|
|
ExpectIntEQ(DecodeExtensionType(ext, len, CERT_POLICY_OID, 1, &cert,
|
|
&isUnknown), WC_NO_ERR_TRACE(ASN_CRIT_EXT_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
|
|
/* Non-critical: RFC 5280 4.2 lets a relying party ignore a non-critical
|
|
* extension it cannot fully process, so an over-limit non-critical
|
|
* certificatePolicies is still accepted (this is what FPKI certs, which
|
|
* carry many non-critical policies, rely on). */
|
|
len = test_certpol_build(ext, MAX_CERTPOL_NB + 1);
|
|
isUnknown = 0;
|
|
wc_InitDecodedCert(&cert, ext, len, NULL);
|
|
ExpectIntEQ(DecodeExtensionType(ext, len, CERT_POLICY_OID, 0, &cert,
|
|
&isUnknown), 0);
|
|
/* The policies that fit are still stored. */
|
|
ExpectIntEQ(cert.extCertPoliciesNb, MAX_CERTPOL_NB);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* A single policy is still accepted. */
|
|
len = test_certpol_build(ext, 1);
|
|
isUnknown = 0;
|
|
wc_InitDecodedCert(&cert, ext, len, NULL);
|
|
ExpectIntEQ(DecodeExtensionType(ext, len, CERT_POLICY_OID, 1, &cert,
|
|
&isUnknown), 0);
|
|
ExpectIntEQ(cert.extCertPoliciesNb, 1);
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_ParseCert_SM3wSM2_short_pubkey(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_SKID) && \
|
|
defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
|
|
/* Malformed cert: the SubjectPublicKeyInfo is an id-ecPublicKey key on the
|
|
* sm2p256v1 curve with only a 4-byte public key body, whole SPKI is 30
|
|
* bytes with no subjectKeyIdentifier extension and SKID derived from the
|
|
* key. */
|
|
static const byte sm2ShortKeyCert[] = {
|
|
0x30, 0x81, 0xa7,
|
|
0x30, 0x56,
|
|
0xa0, 0x03, 0x02, 0x01, 0x02,
|
|
0x02, 0x01, 0x01,
|
|
0x30, 0x0a, 0x06, 0x08,
|
|
0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x75,
|
|
0x30, 0x00,
|
|
0x30, 0x1e,
|
|
0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33,
|
|
0x32, 0x30, 0x34, 0x31, 0x32, 0x31, 0x5a,
|
|
0x17, 0x0d, 0x32, 0x38, 0x30, 0x38, 0x30, 0x39,
|
|
0x32, 0x30, 0x34, 0x31, 0x32, 0x31, 0x5a,
|
|
0x30, 0x00,
|
|
0x30, 0x1c,
|
|
0x30, 0x13,
|
|
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
|
|
0x06, 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x82, 0x2d,
|
|
0x03, 0x05, 0x00, 0x04, 0x11, 0x22, 0x33,
|
|
0x30, 0x0a, 0x06, 0x08,
|
|
0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x75,
|
|
0x03, 0x41, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
DecodedCert cert;
|
|
|
|
wc_InitDecodedCert(&cert, sm2ShortKeyCert, (word32)sizeof(sm2ShortKeyCert),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(BUFFER_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_RSA)
|
|
/* Fixed pieces of a hand-built certificate, shared by the tests below that
|
|
* assemble one around a subject or issuer Name of their own. Laid out in the
|
|
* order they appear in the encoding:
|
|
* dnb_certPreIssuer | <issuer Name> | dnb_certValidity | <subject Name> |
|
|
* dnb_rsaSpki | dnb_certSuffix
|
|
* Callers patch the two SEQUENCE lengths once the total size is known. */
|
|
|
|
/* Certificate fields up to (not including) the issuer Name. The two 0x0000
|
|
* placeholders are the outer and tbsCertificate SEQUENCE lengths. */
|
|
static const byte dnb_certPreIssuer[] = {
|
|
/* Certificate SEQUENCE (length patched) */
|
|
0x30, 0x82, 0x00, 0x00,
|
|
/* tbsCertificate SEQUENCE (length patched) */
|
|
0x30, 0x82, 0x00, 0x00,
|
|
/* version [0] INTEGER 2 */
|
|
0xa0, 0x03, 0x02, 0x01, 0x02,
|
|
/* serialNumber INTEGER 1 */
|
|
0x02, 0x01, 0x01,
|
|
/* signature AlgorithmIdentifier: sha256WithRSAEncryption */
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
|
0x0b, 0x05, 0x00
|
|
};
|
|
/* issuer Name: /CN=Test */
|
|
static const byte dnb_issuerCnTest[] = {
|
|
0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
|
0x04, 0x54, 0x65, 0x73, 0x74
|
|
};
|
|
/* validity: notBefore 20000101000000Z, notAfter 20491231235959Z */
|
|
static const byte dnb_certValidity[] = {
|
|
0x30, 0x1e,
|
|
0x17, 0x0d, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
|
|
0x30, 0x30, 0x5a,
|
|
0x17, 0x0d, 0x34, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
|
|
0x35, 0x39, 0x5a
|
|
};
|
|
/* Outer signatureAlgorithm and a placeholder signatureValue. Not checked
|
|
* because NO_VERIFY is used, but the structure must be present. */
|
|
static const byte dnb_certSuffix[] = {
|
|
/* signatureAlgorithm: sha256WithRSAEncryption */
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
|
0x0b, 0x05, 0x00,
|
|
/* signatureValue BIT STRING */
|
|
0x03, 0x05, 0x00, 0xde, 0xad, 0xbe, 0xef
|
|
};
|
|
/* commonName OID (2.5.4.3). */
|
|
static const byte dnb_cnOid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 };
|
|
/* 2048-bit RSA SubjectPublicKeyInfo, extracted with OpenSSL from
|
|
* certs/client-cert.pem, so the key decodes and the parse succeeds. */
|
|
static const byte dnb_rsaSpki[] = {
|
|
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
|
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
|
|
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc3, 0x03, 0xd1,
|
|
0x2b, 0xfe, 0x39, 0xa4, 0x32, 0x45, 0x3b, 0x53, 0xc8, 0x84, 0x2b, 0x2a,
|
|
0x7c, 0x74, 0x9a, 0xbd, 0xaa, 0x2a, 0x52, 0x07, 0x47, 0xd6, 0xa6, 0x36,
|
|
0xb2, 0x07, 0x32, 0x8e, 0xd0, 0xba, 0x69, 0x7b, 0xc6, 0xc3, 0x44, 0x9e,
|
|
0xd4, 0x81, 0x48, 0xfd, 0x2d, 0x68, 0xa2, 0x8b, 0x67, 0xbb, 0xa1, 0x75,
|
|
0xc8, 0x36, 0x2c, 0x4a, 0xd2, 0x1b, 0xf7, 0x8b, 0xba, 0xcf, 0x0d, 0xf9,
|
|
0xef, 0xec, 0xf1, 0x81, 0x1e, 0x7b, 0x9b, 0x03, 0x47, 0x9a, 0xbf, 0x65,
|
|
0xcc, 0x7f, 0x65, 0x24, 0x69, 0xa6, 0xe8, 0x14, 0x89, 0x5b, 0xe4, 0x34,
|
|
0xf7, 0xc5, 0xb0, 0x14, 0x93, 0xf5, 0x67, 0x7b, 0x3a, 0x7a, 0x78, 0xe1,
|
|
0x01, 0x56, 0x56, 0x91, 0xa6, 0x13, 0x42, 0x8d, 0xd2, 0x3c, 0x40, 0x9c,
|
|
0x4c, 0xef, 0xd1, 0x86, 0xdf, 0x37, 0x51, 0x1b, 0x0c, 0xa1, 0x3b, 0xf5,
|
|
0xf1, 0xa3, 0x4a, 0x35, 0xe4, 0xe1, 0xce, 0x96, 0xdf, 0x1b, 0x7e, 0xbf,
|
|
0x4e, 0x97, 0xd0, 0x10, 0xe8, 0xa8, 0x08, 0x30, 0x81, 0xaf, 0x20, 0x0b,
|
|
0x43, 0x14, 0xc5, 0x74, 0x67, 0xb4, 0x32, 0x82, 0x6f, 0x8d, 0x86, 0xc2,
|
|
0x88, 0x40, 0x99, 0x36, 0x83, 0xba, 0x1e, 0x40, 0x72, 0x22, 0x17, 0xd7,
|
|
0x52, 0x65, 0x24, 0x73, 0xb0, 0xce, 0xef, 0x19, 0xcd, 0xae, 0xff, 0x78,
|
|
0x6c, 0x7b, 0xc0, 0x12, 0x03, 0xd4, 0x4e, 0x72, 0x0d, 0x50, 0x6d, 0x3b,
|
|
0xa3, 0x3b, 0xa3, 0x99, 0x5e, 0x9d, 0xc8, 0xd9, 0x0c, 0x85, 0xb3, 0xd9,
|
|
0x8a, 0xd9, 0x54, 0x26, 0xdb, 0x6d, 0xfa, 0xac, 0xbb, 0xff, 0x25, 0x4c,
|
|
0xc4, 0xd1, 0x79, 0xf4, 0x71, 0xd3, 0x86, 0x40, 0x18, 0x13, 0xb0, 0x63,
|
|
0xb5, 0x72, 0x4e, 0x30, 0xc4, 0x97, 0x84, 0x86, 0x2d, 0x56, 0x2f, 0xd7,
|
|
0x15, 0xf7, 0x7f, 0xc0, 0xae, 0xf5, 0xfc, 0x5b, 0xe5, 0xfb, 0xa1, 0xba,
|
|
0xd3, 0x02, 0x03, 0x01, 0x00, 0x01
|
|
};
|
|
|
|
/* Number of bytes needed to DER-encode the definite length "len".
|
|
* Only handles len < 0x10000, which is all this test needs. */
|
|
static int dnb_lenSz(int len)
|
|
{
|
|
if (len < 0x80)
|
|
return 1;
|
|
if (len < 0x100)
|
|
return 2;
|
|
return 3;
|
|
}
|
|
|
|
/* Write the DER definite length "len" to out. Returns the bytes written. */
|
|
static int dnb_encodeLen(byte* out, int len)
|
|
{
|
|
int i = 0;
|
|
|
|
if (len < 0x80) {
|
|
out[i++] = (byte)len;
|
|
}
|
|
else if (len < 0x100) {
|
|
out[i++] = 0x81;
|
|
out[i++] = (byte)len;
|
|
}
|
|
else {
|
|
out[i++] = 0x82;
|
|
out[i++] = (byte)(len >> 8);
|
|
out[i++] = (byte)(len & 0xff);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/* Build one RDN: SET { SEQUENCE { <oidTlv>, <valTag> <val> } }, where oidTlv is
|
|
* the full DER attribute-type OID (tag, length and content). Returns the total
|
|
* number of bytes written to out. */
|
|
static int dnb_buildRdn(byte* out, const byte* oidTlv, int oidTlvLen,
|
|
byte valTag, const byte* val, int valLen)
|
|
{
|
|
int attrTlvLen;
|
|
int seqContentLen;
|
|
int setContentLen;
|
|
int idx = 0;
|
|
|
|
attrTlvLen = 1 + dnb_lenSz(valLen) + valLen;
|
|
seqContentLen = oidTlvLen + attrTlvLen;
|
|
setContentLen = 1 + dnb_lenSz(seqContentLen) + seqContentLen;
|
|
|
|
out[idx++] = 0x31; /* SET OF */
|
|
idx += dnb_encodeLen(&out[idx], setContentLen);
|
|
out[idx++] = 0x30; /* SEQUENCE */
|
|
idx += dnb_encodeLen(&out[idx], seqContentLen);
|
|
XMEMCPY(&out[idx], oidTlv, (size_t)oidTlvLen);
|
|
idx += oidTlvLen;
|
|
out[idx++] = valTag; /* string tag */
|
|
idx += dnb_encodeLen(&out[idx], valLen);
|
|
XMEMCPY(&out[idx], val, (size_t)valLen);
|
|
idx += valLen;
|
|
|
|
return idx;
|
|
}
|
|
#endif /* !NO_CERTS && !NO_ASN && !NO_RSA */
|
|
|
|
/* Regression test for a 1-byte out-of-bounds NUL write in GetCertName().
|
|
* When a Subject DN exactly fills the WC_ASN_NAME_MAX character buffer the
|
|
* classic (WOLFSSL_ASN_ORIGINAL) parser wrote the string terminator one byte
|
|
* past cert->subject. Each certificate below is built so its second (boundary)
|
|
* RDN would land the running index on exactly WC_ASN_NAME_MAX, which must now
|
|
* be rejected as too big, leaving only the first RDN. Several attribute types
|
|
* are exercised because the too-big guards differ per attribute: commonName
|
|
* uses the "/CN=" prefix, emailAddress takes the distinct email branch with the
|
|
* longer "/emailAddress=" prefix, and (under WOLFSSL_CERT_EXT) jurisdictionC
|
|
* takes the JOI branch. Each attribute is checked on both boundary sides: at
|
|
* the cap (dropped) and one byte under it (kept in full), so an over-tightening
|
|
* off-by-one on any single guard is caught too. Runs under both ASN parsers. */
|
|
int test_ParseCert_dnBufferBoundary(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_RSA)
|
|
/* emailAddress OID (1.2.840.113549.1.9.1, PKCS#9). */
|
|
static const byte emailOid[] = {
|
|
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01
|
|
};
|
|
#ifdef WOLFSSL_CERT_EXT
|
|
/* jurisdictionCountryName OID (ASN_JOI_PREFIX + ASN_JOI_C). */
|
|
static const byte joiCOid[] = {
|
|
0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
|
|
0x03
|
|
};
|
|
#endif
|
|
/* One entry per boundary attribute. valLen is sized relative to the buffer
|
|
* cap: after the leading /CN=A (index 5) the parser adds copyLen + strLen,
|
|
* where commonName copyLen is 4 ("/CN="), emailAddress copyLen is
|
|
* sizeof(WOLFSSL_EMAIL_ADDR) - 1 ("/emailAddress="), and jurisdictionC
|
|
* copyLen is sizeof(WOLFSSL_JOI_C) - 1 ("/jurisdictionC="). The reject cases
|
|
* land on exactly WC_ASN_NAME_MAX (must be dropped); the accept case lands
|
|
* one byte under (largest name that still fits, must be kept in full). */
|
|
struct {
|
|
const byte* oid;
|
|
int oidLen;
|
|
byte valTag;
|
|
int valLen;
|
|
int expectFull; /* 1: second RDN kept in full; 0: dropped */
|
|
} cases[6];
|
|
DecodedCert cert;
|
|
byte* der = NULL;
|
|
byte* val2 = NULL;
|
|
byte rdn1[16];
|
|
int numCases = 4;
|
|
int valLen;
|
|
int rdn1Len;
|
|
int rdn2Len;
|
|
int nameContentLen;
|
|
int tbsContentLen;
|
|
int outerContentLen;
|
|
int pos;
|
|
int derSz;
|
|
int c;
|
|
|
|
/* Each attribute is tested on both boundary sides: valLen at the cap
|
|
* (copyLen + strLen == WC_ASN_NAME_MAX - idx) must be dropped, and one byte
|
|
* under the cap must be kept in full. Both sides are covered per attribute
|
|
* because the too-big guards are independent comparison sites. */
|
|
/* commonName (final catch-all guard). */
|
|
cases[0].oid = dnb_cnOid;
|
|
cases[0].oidLen = (int)sizeof(dnb_cnOid);
|
|
cases[0].valTag = 0x13; /* PrintableString */
|
|
cases[0].valLen = WC_ASN_NAME_MAX - 9;
|
|
cases[0].expectFull = 0;
|
|
cases[1].oid = dnb_cnOid;
|
|
cases[1].oidLen = (int)sizeof(dnb_cnOid);
|
|
cases[1].valTag = 0x13;
|
|
cases[1].valLen = WC_ASN_NAME_MAX - 10;
|
|
cases[1].expectFull = 1;
|
|
/* emailAddress (distinct email branch guard). */
|
|
cases[2].oid = emailOid;
|
|
cases[2].oidLen = (int)sizeof(emailOid);
|
|
cases[2].valTag = 0x16; /* IA5String */
|
|
cases[2].valLen = WC_ASN_NAME_MAX - 5 -
|
|
((int)sizeof(WOLFSSL_EMAIL_ADDR) - 1);
|
|
cases[2].expectFull = 0;
|
|
cases[3].oid = emailOid;
|
|
cases[3].oidLen = (int)sizeof(emailOid);
|
|
cases[3].valTag = 0x16;
|
|
cases[3].valLen = WC_ASN_NAME_MAX - 6 -
|
|
((int)sizeof(WOLFSSL_EMAIL_ADDR) - 1);
|
|
cases[3].expectFull = 1;
|
|
#ifdef WOLFSSL_CERT_EXT
|
|
/* jurisdictionCountryName (JOI branch guard). */
|
|
cases[4].oid = joiCOid;
|
|
cases[4].oidLen = (int)sizeof(joiCOid);
|
|
cases[4].valTag = 0x13; /* PrintableString */
|
|
cases[4].valLen = WC_ASN_NAME_MAX - 5 -
|
|
((int)sizeof(WOLFSSL_JOI_C) - 1);
|
|
cases[4].expectFull = 0;
|
|
cases[5].oid = joiCOid;
|
|
cases[5].oidLen = (int)sizeof(joiCOid);
|
|
cases[5].valTag = 0x13;
|
|
cases[5].valLen = WC_ASN_NAME_MAX - 6 -
|
|
((int)sizeof(WOLFSSL_JOI_C) - 1);
|
|
cases[5].expectFull = 1;
|
|
numCases = 6;
|
|
#endif
|
|
|
|
ExpectNotNull(val2 = (byte*)XMALLOC((size_t)WC_ASN_NAME_MAX, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
ExpectNotNull(der = (byte*)XMALLOC(2048, NULL, DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
for (c = 0; (der != NULL) && (val2 != NULL) && (c < numCases); c++) {
|
|
valLen = cases[c].valLen;
|
|
XMEMSET(val2, 'B', (size_t)valLen);
|
|
|
|
/* Fixed leading fields: everything up to the subject Name. */
|
|
XMEMCPY(der, dnb_certPreIssuer, sizeof(dnb_certPreIssuer));
|
|
pos = (int)sizeof(dnb_certPreIssuer);
|
|
XMEMCPY(&der[pos], dnb_issuerCnTest, sizeof(dnb_issuerCnTest));
|
|
pos += (int)sizeof(dnb_issuerCnTest);
|
|
XMEMCPY(&der[pos], dnb_certValidity, sizeof(dnb_certValidity));
|
|
pos += (int)sizeof(dnb_certValidity);
|
|
|
|
/* First RDN: /CN=A (a short name that must survive). */
|
|
rdn1Len = dnb_buildRdn(rdn1, dnb_cnOid, (int)sizeof(dnb_cnOid), 0x13,
|
|
(const byte*)"A", 1);
|
|
|
|
/* Second RDN length, computed the same way dnb_buildRdn() lays it
|
|
* out. */
|
|
rdn2Len = 1 + dnb_lenSz(valLen) + valLen; /* value TLV */
|
|
rdn2Len = cases[c].oidLen + rdn2Len; /* SEQUENCE content */
|
|
rdn2Len = 1 + dnb_lenSz(rdn2Len) + rdn2Len; /* SET content */
|
|
rdn2Len = 1 + dnb_lenSz(rdn2Len) + rdn2Len; /* SET TLV */
|
|
nameContentLen = rdn1Len + rdn2Len;
|
|
|
|
/* Subject Name SEQUENCE header, then the two RDNs in order. */
|
|
der[pos++] = 0x30;
|
|
pos += dnb_encodeLen(&der[pos], nameContentLen);
|
|
XMEMCPY(&der[pos], rdn1, (size_t)rdn1Len);
|
|
pos += rdn1Len;
|
|
pos += dnb_buildRdn(&der[pos], cases[c].oid, cases[c].oidLen,
|
|
cases[c].valTag, val2, valLen);
|
|
|
|
/* SubjectPublicKeyInfo. */
|
|
XMEMCPY(&der[pos], dnb_rsaSpki, sizeof(dnb_rsaSpki));
|
|
pos += (int)sizeof(dnb_rsaSpki);
|
|
|
|
/* tbsCertificate content spans from offset 8 to here. */
|
|
tbsContentLen = pos - 8;
|
|
|
|
/* Outer signature algorithm and value. */
|
|
XMEMCPY(&der[pos], dnb_certSuffix, sizeof(dnb_certSuffix));
|
|
pos += (int)sizeof(dnb_certSuffix);
|
|
derSz = pos;
|
|
outerContentLen = derSz - 4;
|
|
|
|
/* Patch the two SEQUENCE lengths (both use the 0x82 long form). */
|
|
der[6] = (byte)(tbsContentLen >> 8);
|
|
der[7] = (byte)(tbsContentLen & 0xff);
|
|
der[2] = (byte)(outerContentLen >> 8);
|
|
der[3] = (byte)(outerContentLen & 0xff);
|
|
|
|
wc_InitDecodedCert(&cert, der, (word32)derSz, NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
if (cases[c].expectFull) {
|
|
/* Largest name that still fits: the second RDN is kept and the
|
|
* subject fills the buffer up to the in-bounds terminator. */
|
|
ExpectIntEQ((int)XSTRLEN(cert.subject), WC_ASN_NAME_MAX - 1);
|
|
}
|
|
else {
|
|
/* The boundary attribute is dropped so the terminator stays in
|
|
* bounds; only the first RDN remains. */
|
|
ExpectStrEQ(cert.subject, "/CN=A");
|
|
}
|
|
wc_FreeDecodedCert(&cert);
|
|
}
|
|
|
|
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(val2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif /* !NO_CERTS && !NO_ASN && !NO_RSA */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_ASN_TEMPLATE)
|
|
/* Assemble a certificate around the given issuer and subject Name encodings.
|
|
* Returns the number of DER bytes written to der, which must have room for
|
|
* the fixed parts plus both names. */
|
|
static int cni_buildCert(byte* der, const byte* issuer, int issuerLen,
|
|
const byte* subject, int subjectLen)
|
|
{
|
|
int pos = 0;
|
|
int tbsContentLen;
|
|
int outerContentLen;
|
|
|
|
XMEMCPY(&der[pos], dnb_certPreIssuer, sizeof(dnb_certPreIssuer));
|
|
pos += (int)sizeof(dnb_certPreIssuer);
|
|
XMEMCPY(&der[pos], issuer, (size_t)issuerLen);
|
|
pos += issuerLen;
|
|
XMEMCPY(&der[pos], dnb_certValidity, sizeof(dnb_certValidity));
|
|
pos += (int)sizeof(dnb_certValidity);
|
|
XMEMCPY(&der[pos], subject, (size_t)subjectLen);
|
|
pos += subjectLen;
|
|
XMEMCPY(&der[pos], dnb_rsaSpki, sizeof(dnb_rsaSpki));
|
|
pos += (int)sizeof(dnb_rsaSpki);
|
|
|
|
/* tbsCertificate content spans from offset 8 to here. */
|
|
tbsContentLen = pos - 8;
|
|
|
|
XMEMCPY(&der[pos], dnb_certSuffix, sizeof(dnb_certSuffix));
|
|
pos += (int)sizeof(dnb_certSuffix);
|
|
outerContentLen = pos - 4;
|
|
|
|
/* Patch the two SEQUENCE lengths (both use the 0x82 long form). */
|
|
der[6] = (byte)(tbsContentLen >> 8);
|
|
der[7] = (byte)(tbsContentLen & 0xff);
|
|
der[2] = (byte)(outerContentLen >> 8);
|
|
der[3] = (byte)(outerContentLen & 0xff);
|
|
|
|
return pos;
|
|
}
|
|
|
|
/* Build a Name of /CN=<cn> followed by one PrintableString attribute of type
|
|
* oidTlv. Pass a NULL oidTlv for a Name with just the commonName. Returns the
|
|
* number of bytes written to out or -1 if it does not fit.
|
|
*
|
|
* PrintableString rather than UTF8String on purpose: InitDecodedCert() presets
|
|
* the encoding fields of the components stored from the table to CTC_UTF8, so
|
|
* a test that encoded its values as UTF8String could not tell a stored
|
|
* encoding from the preset one. */
|
|
static int cni_buildName(byte* out, word32 outSz, const char* cn,
|
|
const byte* oidTlv, int oidTlvLen, const char* val)
|
|
{
|
|
byte rdns[128];
|
|
int rdnsLen;
|
|
int idx = 0;
|
|
|
|
rdnsLen = dnb_buildRdn(rdns, dnb_cnOid, (int)sizeof(dnb_cnOid), 0x13,
|
|
(const byte*)cn, (int)XSTRLEN(cn));
|
|
if (oidTlv != NULL) {
|
|
rdnsLen += dnb_buildRdn(&rdns[rdnsLen], oidTlv, oidTlvLen, 0x13,
|
|
(const byte*)val, (int)XSTRLEN(val));
|
|
}
|
|
|
|
/* What the RDNs came to decides the size of the Name: only write it out
|
|
* when the SEQUENCE header and the RDNs fit. */
|
|
if ((rdnsLen > (int)sizeof(rdns)) ||
|
|
((word32)(1 + dnb_lenSz(rdnsLen) + rdnsLen) > outSz)) {
|
|
return -1;
|
|
}
|
|
|
|
out[idx++] = 0x30; /* SEQUENCE */
|
|
idx += dnb_encodeLen(&out[idx], rdnsLen);
|
|
XMEMCPY(&out[idx], rdns, (size_t)rdnsLen);
|
|
idx += rdnsLen;
|
|
|
|
return idx;
|
|
}
|
|
#endif /* !NO_CERTS && !NO_ASN && !NO_RSA && WOLFSSL_ASN_TEMPLATE */
|
|
|
|
/* The name component table in asn.c holds two runs of attribute ids - 2.5.4.3
|
|
* to 2.5.4.18 and, with WOLFSSL_CERT_NAME_ALL, 2.5.4.41 to 2.5.4.46 - with a
|
|
* gap between them, so a row's position is not "id - 3". Indexing it that way
|
|
* put the second run's rows on 2.5.4.19 - 2.5.4.22: those attributes were
|
|
* reported under the labels and NIDs of the second run, and the attributes the
|
|
* rows were written for were dropped instead. Each id is checked here against
|
|
* the label it must produce, including the ones that must produce none. */
|
|
int test_ParseCert_nameComponentIds(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_ASN_TEMPLATE)
|
|
/* Attribute value used for every case. */
|
|
static const char attrVal[] = "VALUE";
|
|
struct {
|
|
byte arc; /* last arc of the 2.5.4.x attribute OID */
|
|
const char* expStr; /* label it must carry, NULL if not recognized */
|
|
} cases[] = {
|
|
/* First run - unaffected by the gap, checked so a change to the
|
|
* mapping cannot quietly break them. */
|
|
{ 0x03, "/CN=" }, /* commonName */
|
|
{ 0x0b, "/OU=" }, /* organizationalUnitName */
|
|
{ 0x12, "/userid=" }, /* userId */
|
|
/* The gap. These are real attributes wolfSSL has no rows for, and are
|
|
* where the second run's rows used to land. */
|
|
{ 0x13, NULL }, /* physicalDeliveryOfficeName */
|
|
{ 0x14, NULL }, /* telephoneNumber */
|
|
{ 0x15, NULL }, /* telexNumber */
|
|
{ 0x16, NULL }, /* teletexTerminalIdentifier */
|
|
/* Second run. */
|
|
#ifdef WOLFSSL_CERT_NAME_ALL
|
|
{ 0x29, "/N=" }, /* name */
|
|
{ 0x2a, "/GN=" }, /* givenName */
|
|
{ 0x2b, "/initials=" }, /* initials */
|
|
{ 0x2e, "/dnQualifier=" }, /* dnQualifier */
|
|
#else
|
|
{ 0x29, NULL },
|
|
{ 0x2a, NULL },
|
|
{ 0x2b, NULL },
|
|
{ 0x2e, NULL },
|
|
#endif
|
|
/* Placeholder rows keep the second run contiguous. 2.5.4.44 has no
|
|
* label, and 2.5.4.45 keeps the one GetRDN() gives it directly - its
|
|
* value is a BIT STRING rather than a DirectoryString. */
|
|
{ 0x2c, NULL }, /* generationQualifier */
|
|
{ 0x2d, WOLFSSL_X500_UNIQUE_ID } /* x500UniqueIdentifier */
|
|
};
|
|
DecodedCert cert;
|
|
byte arcOid[5] = { 0x06, 0x03, 0x55, 0x04, 0x00 };
|
|
byte issuer[64];
|
|
byte subject[64];
|
|
byte* der = NULL;
|
|
char expect[64];
|
|
int issuerLen;
|
|
int subjectLen;
|
|
int derSz;
|
|
int c;
|
|
|
|
ExpectNotNull(der = (byte*)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
issuerLen = cni_buildName(issuer, (word32)sizeof(issuer), "Test", NULL, 0,
|
|
NULL);
|
|
ExpectIntGT(issuerLen, 0);
|
|
|
|
for (c = 0; (der != NULL) && (issuerLen > 0) &&
|
|
(c < (int)XELEM_CNT(cases)); c++) {
|
|
arcOid[4] = cases[c].arc;
|
|
subjectLen = cni_buildName(subject, (word32)sizeof(subject), "S",
|
|
arcOid, (int)sizeof(arcOid), attrVal);
|
|
ExpectIntGT(subjectLen, 0);
|
|
if (subjectLen < 0) {
|
|
break;
|
|
}
|
|
derSz = cni_buildCert(der, issuer, issuerLen, subject, subjectLen);
|
|
|
|
wc_InitDecodedCert(&cert, der, (word32)derSz, NULL);
|
|
/* An attribute with no row is skipped, not an error. */
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
|
|
if (cases[c].expStr == NULL) {
|
|
/* Nothing but the commonName may reach the subject string. */
|
|
ExpectStrEQ(cert.subject, "/CN=S");
|
|
}
|
|
else {
|
|
XSTRLCPY(expect, "/CN=S", sizeof(expect));
|
|
XSTRLCAT(expect, cases[c].expStr, sizeof(expect));
|
|
XSTRLCAT(expect, attrVal, sizeof(expect));
|
|
ExpectStrEQ(cert.subject, expect);
|
|
}
|
|
|
|
#if defined(WOLFSSL_CERT_NAME_ALL) && (defined(WOLFSSL_CERT_GEN) || \
|
|
defined(WOLFSSL_CERT_EXT))
|
|
/* Components of the second run are also stored in DecodedCert: the
|
|
* value, its length and its encoding, all of which come from the row's
|
|
* offsets, so a row pointing at the wrong field is only caught by
|
|
* checking the value itself. The ids in the gap must leave those
|
|
* fields alone. */
|
|
switch (cases[c].arc) {
|
|
case 0x29:
|
|
ExpectNotNull(cert.subjectN);
|
|
ExpectIntEQ(cert.subjectNLen, (int)XSTRLEN(attrVal));
|
|
ExpectIntEQ(XMEMCMP(cert.subjectN, attrVal,
|
|
XSTRLEN(attrVal)), 0);
|
|
ExpectIntEQ(cert.subjectNEnc, ASN_PRINTABLE_STRING);
|
|
break;
|
|
case 0x2a:
|
|
ExpectNotNull(cert.subjectGN);
|
|
ExpectIntEQ(cert.subjectGNLen, (int)XSTRLEN(attrVal));
|
|
ExpectIntEQ(XMEMCMP(cert.subjectGN, attrVal,
|
|
XSTRLEN(attrVal)), 0);
|
|
ExpectIntEQ(cert.subjectGNEnc, ASN_PRINTABLE_STRING);
|
|
break;
|
|
case 0x2b:
|
|
ExpectNotNull(cert.subjectI);
|
|
ExpectIntEQ(cert.subjectILen, (int)XSTRLEN(attrVal));
|
|
ExpectIntEQ(XMEMCMP(cert.subjectI, attrVal,
|
|
XSTRLEN(attrVal)), 0);
|
|
ExpectIntEQ(cert.subjectIEnc, ASN_PRINTABLE_STRING);
|
|
break;
|
|
case 0x2e:
|
|
ExpectNotNull(cert.subjectDNQ);
|
|
ExpectIntEQ(cert.subjectDNQLen, (int)XSTRLEN(attrVal));
|
|
ExpectIntEQ(XMEMCMP(cert.subjectDNQ, attrVal,
|
|
XSTRLEN(attrVal)), 0);
|
|
ExpectIntEQ(cert.subjectDNQEnc, ASN_PRINTABLE_STRING);
|
|
break;
|
|
default:
|
|
ExpectNull(cert.subjectN);
|
|
ExpectNull(cert.subjectGN);
|
|
ExpectNull(cert.subjectI);
|
|
ExpectNull(cert.subjectDNQ);
|
|
break;
|
|
}
|
|
#endif
|
|
wc_FreeDecodedCert(&cert);
|
|
}
|
|
|
|
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif /* !NO_CERTS && !NO_ASN && !NO_RSA && WOLFSSL_ASN_TEMPLATE */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Rows of the name component table carry offsets into DecodedCert, and a row
|
|
* with no field for a component has a zero offset. Offset zero is the start of
|
|
* DecodedCert, so storing through such a row writes over its first member
|
|
* rather than a name field. Most rows have no issuer fields, which made the
|
|
* issuer side the reachable case - including every row of the second run of
|
|
* ids, which reaches the same guard through the other range of
|
|
* CertNameSubjectIdx() and so is driven here too. */
|
|
int test_ParseCert_issuerNameNoField(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_ISSUER_NAMES) && \
|
|
(defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT))
|
|
/* Attribute value used for every case. */
|
|
static const char attrVal[] = "VALUE";
|
|
/* An unassigned pilot attribute type (0.9.2342.19200300.100.1.99). GetRDN()
|
|
* rejects it, which stops the parse after the issuer name has been read and
|
|
* before the public key is, leaving whatever the issuer name wrote to
|
|
* DecodedCert's first member in place. */
|
|
static const byte badPilotOid[] = {
|
|
0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x63
|
|
};
|
|
/* Issuer attributes whose rows have no issuer fields in DecodedCert. Each
|
|
* must still be reported in the issuer string and must store nothing. */
|
|
struct {
|
|
byte arc; /* last arc of the 2.5.4.x attribute OID */
|
|
const char* expStr; /* label it must carry */
|
|
} cases[] = {
|
|
/* First run of ids. Has subject fields but no issuer ones. */
|
|
{ 0x09, "/street=" }, /* streetAddress */
|
|
{ 0x11, "/postalCode=" }, /* postalCode */
|
|
#ifdef WOLFSSL_CERT_NAME_ALL
|
|
/* Second run of ids - mapped by the other range of
|
|
* CertNameSubjectIdx(), and with no issuer fields either. */
|
|
{ 0x29, "/N=" }, /* name */
|
|
{ 0x2b, "/initials=" }, /* initials */
|
|
{ 0x2e, "/dnQualifier=" } /* dnQualifier */
|
|
#endif
|
|
};
|
|
DecodedCert cert;
|
|
byte arcOid[5] = { 0x06, 0x03, 0x55, 0x04, 0x00 };
|
|
byte issuer[64];
|
|
byte subject[64];
|
|
byte* der = NULL;
|
|
char expect[64];
|
|
int issuerLen;
|
|
int subjectLen;
|
|
int derSz;
|
|
int c;
|
|
|
|
ExpectNotNull(der = (byte*)XMALLOC(1024, NULL, DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
subjectLen = cni_buildName(subject, (word32)sizeof(subject), "S",
|
|
badPilotOid, (int)sizeof(badPilotOid), "unknown");
|
|
ExpectIntGT(subjectLen, 0);
|
|
|
|
for (c = 0; (der != NULL) && (subjectLen > 0) &&
|
|
(c < (int)XELEM_CNT(cases)); c++) {
|
|
arcOid[4] = cases[c].arc;
|
|
issuerLen = cni_buildName(issuer, (word32)sizeof(issuer), "I", arcOid,
|
|
(int)sizeof(arcOid), attrVal);
|
|
ExpectIntGT(issuerLen, 0);
|
|
if (issuerLen < 0) {
|
|
break;
|
|
}
|
|
derSz = cni_buildCert(der, issuer, issuerLen, subject, subjectLen);
|
|
|
|
wc_InitDecodedCert(&cert, der, (word32)derSz, NULL);
|
|
ExpectIntNE(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
|
|
/* The component is still reported in the issuer string, under the
|
|
* label its row carries. */
|
|
XSTRLCPY(expect, "/CN=I", sizeof(expect));
|
|
XSTRLCAT(expect, cases[c].expStr, sizeof(expect));
|
|
XSTRLCAT(expect, attrVal, sizeof(expect));
|
|
ExpectStrEQ(cert.issuer, expect);
|
|
|
|
/* DecodedCert's first member must be untouched: nothing has set the
|
|
* public key on this path, so a store through a zero offset is the
|
|
* only thing that could have. */
|
|
ExpectNull(cert.publicKey);
|
|
wc_FreeDecodedCert(&cert);
|
|
}
|
|
|
|
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_SerialNumber0_RootCA(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
!defined(WOLFSSL_NO_PEM) && defined(WOLFSSL_PEM_TO_DER)
|
|
/* Test that root CA certificates with serial number 0 are accepted,
|
|
* while non-root certificates with serial 0 are rejected (issue #8615) */
|
|
|
|
#if !defined(WOLFSSL_NO_ASN_STRICT) && !defined(WOLFSSL_PYTHON) && \
|
|
!defined(WOLFSSL_ASN_ALLOW_0_SERIAL) && \
|
|
!defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
|
|
WOLFSSL_CERT_MANAGER* cm = NULL;
|
|
const char* rootSerial0File = "./certs/test-serial0/root_serial0.pem";
|
|
const char* selfSignedNonCASerial0File =
|
|
"./certs/test-serial0/selfsigned_nonca_serial0.pem";
|
|
|
|
/* Test 1: Root CA with serial 0 should load successfully */
|
|
ExpectNotNull(cm = wolfSSL_CertManagerNew());
|
|
ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm, rootSerial0File, NULL),
|
|
WOLFSSL_SUCCESS);
|
|
|
|
#if (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) || \
|
|
defined(OPENSSL_EXTRA)
|
|
{
|
|
const char* eeSerial0File = "./certs/test-serial0/ee_serial0.pem";
|
|
const char* eeNormalFile = "./certs/test-serial0/ee_normal.pem";
|
|
|
|
/* Test 2: End-entity cert with serial 0 should be rejected during
|
|
* verify */
|
|
ExpectIntEQ(wolfSSL_CertManagerVerify(cm, eeSerial0File,
|
|
WOLFSSL_FILETYPE_PEM), WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
|
|
/* Test 3: Normal end-entity cert signed by root CA with serial 0
|
|
* should verify successfully */
|
|
ExpectIntEQ(wolfSSL_CertManagerVerify(cm, eeNormalFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
if (cm != NULL) {
|
|
wolfSSL_CertManagerFree(cm);
|
|
cm = NULL;
|
|
}
|
|
|
|
/* Test 4: Self-signed non-CA certificate with serial 0 should be rejected */
|
|
ExpectNotNull(cm = wolfSSL_CertManagerNew());
|
|
ExpectIntNE(wolfSSL_CertManagerLoadCA(cm, selfSignedNonCASerial0File, NULL),
|
|
WOLFSSL_SUCCESS);
|
|
|
|
if (cm != NULL) {
|
|
wolfSSL_CertManagerFree(cm);
|
|
cm = NULL;
|
|
}
|
|
|
|
/* Test 5: Intermediate CA (CA:TRUE but issuer != subject) with serial 0
|
|
* must be rejected when loaded as CA_TYPE. Exercises the selfIssued
|
|
* half of the ParseCertRelative exemption predicate. */
|
|
{
|
|
const char* intermediateSerial0File =
|
|
"./certs/test-serial0/intermediate_serial0.pem";
|
|
ExpectNotNull(cm = wolfSSL_CertManagerNew());
|
|
ExpectIntNE(wolfSSL_CertManagerLoadCA(cm, intermediateSerial0File,
|
|
NULL), WOLFSSL_SUCCESS);
|
|
if (cm != NULL) {
|
|
wolfSSL_CertManagerFree(cm);
|
|
cm = NULL;
|
|
}
|
|
}
|
|
#endif /* !WOLFSSL_NO_ASN_STRICT && !WOLFSSL_PYTHON &&
|
|
!WOLFSSL_ASN_ALLOW_0_SERIAL &&
|
|
!WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION */
|
|
#endif /* !NO_CERTS && !NO_FILESYSTEM && !NO_RSA && !WOLFSSL_NO_PEM */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_wc_DecodeObjectId(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_ASN) && \
|
|
(defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT))
|
|
{
|
|
/* OID 1.2.840.113549.1.1.11 (sha256WithRSAEncryption)
|
|
* DER encoding: 2a 86 48 86 f7 0d 01 01 0b
|
|
* First byte 0x2a = 42 => arc0 = 42/40 = 1, arc1 = 42%40 = 2
|
|
* Remaining arcs: 840, 113549, 1, 1, 11
|
|
*/
|
|
static const byte oid_sha256rsa[] = {
|
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
|
|
};
|
|
word16 out[MAX_OID_SZ];
|
|
word32 outSz;
|
|
|
|
/* Test 1: Normal decode */
|
|
outSz = MAX_OID_SZ;
|
|
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
|
|
out, &outSz), 0);
|
|
ExpectIntEQ((int)outSz, 7);
|
|
ExpectIntEQ(out[0], 1);
|
|
ExpectIntEQ(out[1], 2);
|
|
ExpectIntEQ(out[2], 840);
|
|
ExpectIntEQ(out[3], (word16)113549); /* truncated to word16 */
|
|
ExpectIntEQ(out[4], 1);
|
|
ExpectIntEQ(out[5], 1);
|
|
ExpectIntEQ(out[6], 11);
|
|
|
|
/* Test 2: NULL args */
|
|
outSz = MAX_OID_SZ;
|
|
ExpectIntEQ(DecodeObjectId(NULL, sizeof(oid_sha256rsa), out, &outSz),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
|
|
out, NULL),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
/* Test 3 (Bug 1): outSz=1 must return BUFFER_E, not OOB write.
|
|
* The first OID byte decodes into two arcs, so outSz must be >= 2. */
|
|
outSz = 1;
|
|
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
|
|
out, &outSz),
|
|
WC_NO_ERR_TRACE(BUFFER_E));
|
|
|
|
/* Test 4: outSz=0 must also return BUFFER_E */
|
|
outSz = 0;
|
|
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
|
|
out, &outSz),
|
|
WC_NO_ERR_TRACE(BUFFER_E));
|
|
|
|
/* Test 5: outSz=2 is enough for a single-byte OID (two arcs) */
|
|
{
|
|
static const byte oid_one_byte[] = { 0x2a }; /* 1.2 */
|
|
outSz = 2;
|
|
ExpectIntEQ(DecodeObjectId(oid_one_byte, sizeof(oid_one_byte),
|
|
out, &outSz), 0);
|
|
ExpectIntEQ((int)outSz, 2);
|
|
ExpectIntEQ(out[0], 1);
|
|
ExpectIntEQ(out[1], 2);
|
|
}
|
|
|
|
/* Test 6: Buffer too small for later arcs */
|
|
outSz = 3; /* only room for 3 arcs, but OID has 7 */
|
|
ExpectIntEQ(DecodeObjectId(oid_sha256rsa, sizeof(oid_sha256rsa),
|
|
out, &outSz),
|
|
WC_NO_ERR_TRACE(BUFFER_E));
|
|
}
|
|
#endif /* !NO_ASN && (HAVE_OID_DECODING || WOLFSSL_ASN_PRINT) */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN)) && \
|
|
(defined(HAVE_ED25519) || \
|
|
(defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
|
|
defined(WOLFSSL_KEY_GEN)) || \
|
|
(defined(HAVE_DILITHIUM) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_ASN1)))
|
|
/* Run ToTraditional_ex() on a copy of der and assert the algId, returned
|
|
* length, and the inner OCTET STRING tag/length at the start of the
|
|
* (in-place rewritten) buffer. */
|
|
static int test_ToTraditional_ex_once(const byte* der, word32 derSz,
|
|
word32 expectAlgId, word32 expectPrivKeySz)
|
|
{
|
|
EXPECT_DECLS;
|
|
byte* copy = NULL;
|
|
word32 algId = 0;
|
|
int ret;
|
|
|
|
copy = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
ExpectNotNull(copy);
|
|
if (copy != NULL) {
|
|
XMEMCPY(copy, der, derSz);
|
|
ret = ToTraditional_ex(copy, derSz, &algId);
|
|
ExpectIntGT(ret, 0);
|
|
ExpectIntEQ(algId, expectAlgId);
|
|
if (ret > 0) {
|
|
/* wolfSSL writes nested OCTET STRING, but accept raw bytes
|
|
* too per RFC 5958. */
|
|
if (copy[0] == ASN_OCTET_STRING) {
|
|
if (expectPrivKeySz < 0x80) {
|
|
ExpectIntEQ(copy[1], (byte)expectPrivKeySz);
|
|
}
|
|
else if (expectPrivKeySz < 0x100) {
|
|
ExpectIntEQ(copy[1], 0x81);
|
|
ExpectIntEQ(copy[2], (byte)expectPrivKeySz);
|
|
}
|
|
else {
|
|
ExpectIntEQ(copy[1], 0x82);
|
|
ExpectIntEQ(((word32)copy[2] << 8) | copy[3],
|
|
expectPrivKeySz);
|
|
}
|
|
}
|
|
else {
|
|
ExpectIntEQ(ret, (int)expectPrivKeySz);
|
|
}
|
|
}
|
|
}
|
|
XFREE(copy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
#endif
|
|
|
|
/* Hand crafted PKCS#8 v0 and v1 Ed25519 buffers to test parser directly. */
|
|
int test_ToTraditional_ex_handcrafted(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_PKCS8) && defined(HAVE_ED25519) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
|
/* Ed25519 algorithm OID body (1.3.101.112). */
|
|
static const byte algId[] = { 43, 101, 112 };
|
|
const word32 privKeySz = ED25519_KEY_SIZE;
|
|
const word32 pubKeySz = ED25519_PUB_KEY_SIZE;
|
|
byte der[128];
|
|
word32 sz;
|
|
word32 outerLenIdx;
|
|
/* Filler bytes for the dummy private/public key bodies */
|
|
const byte keyPat = 0xCC;
|
|
const byte pubPat = 0xDD;
|
|
|
|
/* v0: SEQ { INTEGER 0, SEQ { OID }, OCTET STRING { OCTET STRING priv } } */
|
|
sz = 0;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
outerLenIdx = sz;
|
|
der[sz++] = 0; /* outer length, filled in below */
|
|
der[sz++] = ASN_INTEGER;
|
|
der[sz++] = 1;
|
|
der[sz++] = 0x00;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
der[sz++] = (byte)(sizeof(algId) + 2);
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(algId);
|
|
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)(privKeySz + 2);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)privKeySz;
|
|
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
|
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
|
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
|
|
|
/* v1: same plus [1] publicKey trailer. */
|
|
sz = 0;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
outerLenIdx = sz;
|
|
der[sz++] = 0;
|
|
der[sz++] = ASN_INTEGER;
|
|
der[sz++] = 1;
|
|
der[sz++] = 0x01;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
der[sz++] = (byte)(sizeof(algId) + 2);
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(algId);
|
|
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)(privKeySz + 2);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)privKeySz;
|
|
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
|
/* [1] publicKey trailer */
|
|
der[sz++] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
|
der[sz++] = (byte)pubKeySz;
|
|
XMEMSET(der + sz, pubPat, pubKeySz); sz += pubKeySz;
|
|
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
|
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
|
|
|
/* v1 without publicKey: should still accept per RFC 5958. */
|
|
sz = 0;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
outerLenIdx = sz;
|
|
der[sz++] = 0;
|
|
der[sz++] = ASN_INTEGER;
|
|
der[sz++] = 1;
|
|
der[sz++] = 0x01;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
der[sz++] = (byte)(sizeof(algId) + 2);
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(algId);
|
|
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)(privKeySz + 2);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)privKeySz;
|
|
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
|
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
|
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
|
#endif /* HAVE_PKCS8 && HAVE_ED25519 */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Encoder/parser round trip: ToTraditional_ex() must accept both forms created
|
|
* by SetAsymKeyDer() (v0 with PrivateKeyToDer, v1 with KeyToDer). */
|
|
int test_ToTraditional_ex_roundtrip(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_PKCS8) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
|
|
|
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
|
|
defined(WOLFSSL_KEY_GEN) && defined(HAVE_ED25519_MAKE_KEY)
|
|
{
|
|
ed25519_key key;
|
|
WC_RNG rng;
|
|
byte der[256];
|
|
int derSz = 0;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
|
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
|
|
|
if (EXPECT_SUCCESS()) {
|
|
ExpectIntGT(derSz = wc_Ed25519KeyToDer(&key, der, sizeof(der)), 0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED25519k,
|
|
ED25519_KEY_SIZE));
|
|
|
|
derSz = wc_Ed25519PrivateKeyToDer(&key, der, sizeof(der));
|
|
ExpectIntGT(derSz, 0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED25519k,
|
|
ED25519_KEY_SIZE));
|
|
}
|
|
|
|
wc_ed25519_free(&key);
|
|
wc_FreeRng(&rng);
|
|
}
|
|
#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_EXPORT && WOLFSSL_KEY_GEN &&
|
|
HAVE_ED25519_MAKE_KEY */
|
|
|
|
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
|
|
defined(WOLFSSL_KEY_GEN)
|
|
{
|
|
ed448_key key;
|
|
WC_RNG rng;
|
|
byte der[256];
|
|
int derSz = 0;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_ed448_init(&key), 0);
|
|
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
|
|
|
|
if (EXPECT_SUCCESS()) {
|
|
ExpectIntGT(derSz = wc_Ed448KeyToDer(&key, der, sizeof(der)), 0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED448k,
|
|
ED448_KEY_SIZE));
|
|
|
|
derSz = wc_Ed448PrivateKeyToDer(&key, der, sizeof(der));
|
|
ExpectIntGT(derSz, 0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED448k,
|
|
ED448_KEY_SIZE));
|
|
}
|
|
|
|
wc_ed448_free(&key);
|
|
wc_FreeRng(&rng);
|
|
}
|
|
#endif /* HAVE_ED448 */
|
|
|
|
#if defined(HAVE_DILITHIUM) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && \
|
|
(!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \
|
|
!defined(WOLFSSL_NO_ML_DSA_87))
|
|
{
|
|
static const struct {
|
|
int wcLevel;
|
|
word32 oidSum;
|
|
word32 privKeySz;
|
|
} variants[] = {
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
{ WC_ML_DSA_44, ML_DSA_LEVEL2k, ML_DSA_LEVEL2_KEY_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
{ WC_ML_DSA_65, ML_DSA_LEVEL3k, ML_DSA_LEVEL3_KEY_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
{ WC_ML_DSA_87, ML_DSA_LEVEL5k, ML_DSA_LEVEL5_KEY_SIZE },
|
|
#endif
|
|
};
|
|
|
|
const word32 derMaxSz = DILITHIUM_MAX_BOTH_KEY_DER_SIZE;
|
|
byte* der = NULL;
|
|
WC_RNG rng;
|
|
size_t i;
|
|
int derSz;
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectNotNull(der = (byte*)XMALLOC(derMaxSz, NULL,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
for (i = 0; i < sizeof(variants) / sizeof(variants[0]); i++) {
|
|
dilithium_key key;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
ExpectIntEQ(wc_dilithium_init(&key), 0);
|
|
ExpectIntEQ(wc_dilithium_set_level(&key, variants[i].wcLevel), 0);
|
|
ExpectIntEQ(wc_dilithium_make_key(&key, &rng), 0);
|
|
|
|
if (EXPECT_SUCCESS()) {
|
|
ExpectIntGT(derSz = wc_Dilithium_KeyToDer(&key, der, derMaxSz),
|
|
0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz,
|
|
variants[i].oidSum, variants[i].privKeySz));
|
|
|
|
derSz = wc_Dilithium_PrivateKeyToDer(&key, der, derMaxSz);
|
|
ExpectIntGT(derSz, 0);
|
|
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz,
|
|
variants[i].oidSum, variants[i].privKeySz));
|
|
}
|
|
|
|
wc_dilithium_free(&key);
|
|
}
|
|
|
|
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
wc_FreeRng(&rng);
|
|
}
|
|
#endif /* HAVE_DILITHIUM */
|
|
|
|
#endif /* HAVE_PKCS8 */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Trailing garbage that is neither [0] attributes nor [1] publicKey must
|
|
* still be rejected. */
|
|
int test_ToTraditional_ex_negative(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_PKCS8) && defined(HAVE_ED25519) && \
|
|
defined(HAVE_ED25519_KEY_EXPORT) && defined(HAVE_ED25519_MAKE_KEY) && \
|
|
defined(WOLFSSL_KEY_GEN) && defined(WOLFSSL_ASN_TEMPLATE) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
|
ed25519_key key;
|
|
WC_RNG rng;
|
|
byte der[256];
|
|
byte copy[256];
|
|
int derSz = 0;
|
|
word32 algId;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
|
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
|
ExpectIntGT(derSz = wc_Ed25519PrivateKeyToDer(&key, der, sizeof(der)), 0);
|
|
|
|
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
|
((size_t)derSz + 1 <= sizeof(copy))) {
|
|
/* Append one byte of trailing data, grow outer SEQ length to cover.
|
|
* Ed25519 PKCS#8 outer SEQ is under 128 bytes, expect DER short form
|
|
* so the negative path is always exercised. */
|
|
XMEMCPY(copy, der, (size_t)derSz);
|
|
ExpectTrue(copy[1] < 0x80);
|
|
if (EXPECT_SUCCESS() && copy[1] < 0x80) {
|
|
copy[1] = (byte)(copy[1] + 1);
|
|
copy[derSz] = 0x05;
|
|
algId = 0;
|
|
ExpectIntLT(ToTraditional_ex(copy, (word32)(derSz + 1), &algId), 0);
|
|
}
|
|
}
|
|
|
|
/* publicKey trailer is permitted only when version == v1 */
|
|
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
|
((size_t)derSz + 2 + ED25519_PUB_KEY_SIZE <= sizeof(copy))) {
|
|
word32 trailerSz = 2 + ED25519_PUB_KEY_SIZE;
|
|
XMEMCPY(copy, der, (size_t)derSz);
|
|
ExpectTrue(copy[1] < (byte)(0x80 - trailerSz));
|
|
if (EXPECT_SUCCESS() && copy[1] < (byte)(0x80 - trailerSz)) {
|
|
copy[1] = (byte)(copy[1] + trailerSz);
|
|
copy[derSz] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
|
copy[derSz + 1] = ED25519_PUB_KEY_SIZE;
|
|
XMEMSET(copy + derSz + 2, 0xDD, ED25519_PUB_KEY_SIZE);
|
|
algId = 0;
|
|
ExpectIntLT(ToTraditional_ex(copy,
|
|
(word32)(derSz + (int)trailerSz), &algId), 0);
|
|
}
|
|
}
|
|
|
|
/* v1 buffer (with publicKey) plus extra trailing garbage. */
|
|
ExpectIntGT(derSz = wc_Ed25519KeyToDer(&key, der, sizeof(der)), 0);
|
|
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
|
((size_t)derSz + 1 <= sizeof(copy))) {
|
|
XMEMCPY(copy, der, (size_t)derSz);
|
|
ExpectTrue(copy[1] < 0x80);
|
|
if (EXPECT_SUCCESS() && copy[1] < 0x80) {
|
|
copy[1] = (byte)(copy[1] + 1);
|
|
copy[derSz] = 0x05;
|
|
algId = 0;
|
|
ExpectIntLT(ToTraditional_ex(copy, (word32)(derSz + 1), &algId), 0);
|
|
}
|
|
}
|
|
|
|
wc_ed25519_free(&key);
|
|
wc_FreeRng(&rng);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* ML-DSA AlgorithmIdentifier has no parameters per FIPS 204. Verify
|
|
* ToTraditional_ex() rejects a PKCS#8 whose algoSeq carries trailing NULL
|
|
* or OBJECT_ID parameters. Template parser only (legacy is lenient). */
|
|
int test_ToTraditional_ex_mldsa_bad_params(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_PKCS8) && defined(HAVE_DILITHIUM) && \
|
|
defined(WOLFSSL_ASN_TEMPLATE) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
|
/* ML-DSA-65 OID body: 2.16.840.1.101.3.4.3.18 */
|
|
static const byte mldsaOid[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
|
0x04, 0x03, 0x12 };
|
|
/* Single-arc OID body, used only to occupy the OBJECT_ID slot. */
|
|
static const byte extraOid[] = { 0x01 };
|
|
byte der[64];
|
|
byte copy[64];
|
|
word32 sz;
|
|
word32 outerLenIdx;
|
|
word32 algId;
|
|
const word32 privKeySz = 4;
|
|
const byte privBody = 0xAA;
|
|
|
|
/* Bad case, algoSeq = { OID, NULL } */
|
|
sz = 0;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
outerLenIdx = sz;
|
|
der[sz++] = 0; /* outer length, filled in below */
|
|
der[sz++] = ASN_INTEGER;
|
|
der[sz++] = 1;
|
|
der[sz++] = 0x00;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + 2);
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(mldsaOid);
|
|
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
|
/* Disallowed, NULL parameter after the ML-DSA OID. */
|
|
der[sz++] = ASN_TAG_NULL;
|
|
der[sz++] = 0;
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)(privKeySz + 2);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)privKeySz;
|
|
XMEMSET(der + sz, privBody, privKeySz); sz += privKeySz;
|
|
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
|
|
|
XMEMCPY(copy, der, sz);
|
|
algId = 0;
|
|
ExpectIntLT(ToTraditional_ex(copy, sz, &algId), 0);
|
|
|
|
/* Bad case, algoSeq = { OID, OBJECT_ID } */
|
|
sz = 0;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
outerLenIdx = sz;
|
|
der[sz++] = 0;
|
|
der[sz++] = ASN_INTEGER;
|
|
der[sz++] = 1;
|
|
der[sz++] = 0x00;
|
|
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + sizeof(extraOid) + 2);
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(mldsaOid);
|
|
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
|
/* Disallowed, OBJECT_ID parameter after the ML-DSA OID. */
|
|
der[sz++] = ASN_OBJECT_ID;
|
|
der[sz++] = (byte)sizeof(extraOid);
|
|
XMEMCPY(der + sz, extraOid, sizeof(extraOid)); sz += sizeof(extraOid);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)(privKeySz + 2);
|
|
der[sz++] = ASN_OCTET_STRING;
|
|
der[sz++] = (byte)privKeySz;
|
|
XMEMSET(der + sz, privBody, privKeySz); sz += privKeySz;
|
|
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
|
|
|
XMEMCPY(copy, der, sz);
|
|
algId = 0;
|
|
ExpectIntLT(ToTraditional_ex(copy, sz, &algId), 0);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* What wc_SignCert() bounds testing needs regardless of the signing algorithm.
|
|
* Each algorithm then gates on its own key type and certificate buffers, so an
|
|
* RSA-less build still gets the ECDSA sweep and vice versa. */
|
|
#if defined(WOLFSSL_CERT_GEN) && !defined(NO_SHA256) && !defined(WC_NO_RNG) && \
|
|
!defined(NO_ASN_TIME) && !defined(NO_ASN_CRYPT)
|
|
#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_2048)
|
|
#define TEST_SIGN_CERT_BOUNDS_RSA
|
|
#endif
|
|
#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
|
|
#define TEST_SIGN_CERT_BOUNDS_ECC
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(TEST_SIGN_CERT_BOUNDS_RSA) || defined(TEST_SIGN_CERT_BOUNDS_ECC)
|
|
|
|
#define SIGN_CERT_SCRATCH_SZ 4096
|
|
/* Number of capacities below the exact encoding size to try. Has to be wider
|
|
* than the AlgorithmIdentifier plus BIT STRING header that a sequence-headers
|
|
* only estimate leaves out. */
|
|
#define SIGN_CERT_BAND_SZ 24
|
|
/* Bytes kept past the advertised capacity to catch a write past the end. */
|
|
#define SIGN_CERT_GUARD_SZ 32
|
|
#define SIGN_CERT_GUARD_BYTE 0xA5
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
/* Build the certificate body used by test_wc_SignCert_buffer_bounds().
|
|
* wc_SignCert() rewrites the buffer in place, so it has to be rebuilt for
|
|
* every capacity tried. Returns the body size or a negative error.
|
|
*
|
|
* The serial is fixed rather than left for wc_MakeCert() to generate. A
|
|
* generated serial is random, and GenerateInteger() does not shrink its length
|
|
* after dropping leading zero bytes, so the promoted byte can carry the MSB and
|
|
* make the encoder pad the INTEGER with an extra 0x00. That changes the body
|
|
* size for about one certificate in 250, which would make the swept capacities
|
|
* below disagree with the reference size. */
|
|
static int test_wc_SignCert_makeBody(Cert* cert, RsaKey* key, WC_RNG* rng,
|
|
byte* out, word32 outSz)
|
|
{
|
|
static const byte serial[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08 };
|
|
int ret;
|
|
|
|
ret = wc_InitCert(cert);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
cert->sigType = CTC_SHA256wRSA;
|
|
cert->isCA = 0;
|
|
XMEMCPY(cert->serial, serial, sizeof(serial));
|
|
cert->serialSz = (int)sizeof(serial);
|
|
XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.state, "MT", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.commonName, "signcert-bounds", CTC_NAME_SIZE);
|
|
|
|
return wc_MakeCert(cert, out, outSz, key, NULL, rng);
|
|
}
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA */
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_ECC
|
|
/* ECDSA r and s are DER INTEGERs whose length changes with the leading zero
|
|
* bytes of each new signature, so an ECDSA encoding size measured once does not
|
|
* repeat. The sweep copes with that by asserting an invariant that holds for
|
|
* either outcome rather than a fixed return, so only the accept case needs a
|
|
* capacity clear of anything the jitter can reach. */
|
|
#define SIGN_CERT_ECC_SLACK 8
|
|
|
|
/* ECDSA counterpart of test_wc_SignCert_makeBody(). */
|
|
static int test_wc_SignCert_makeBodyEcc(Cert* cert, ecc_key* key, WC_RNG* rng,
|
|
byte* out, word32 outSz)
|
|
{
|
|
static const byte serial[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08 };
|
|
int ret;
|
|
|
|
ret = wc_InitCert(cert);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
cert->sigType = CTC_SHA256wECDSA;
|
|
cert->isCA = 0;
|
|
XMEMCPY(cert->serial, serial, sizeof(serial));
|
|
cert->serialSz = (int)sizeof(serial);
|
|
XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.state, "MT", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.commonName, "signcert-bounds-ecc", CTC_NAME_SIZE);
|
|
|
|
return wc_MakeCert(cert, out, outSz, NULL, key, rng);
|
|
}
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_ECC */
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA || TEST_SIGN_CERT_BOUNDS_ECC */
|
|
|
|
/*
|
|
* wc_SignCert() must never write past the capacity it was given.
|
|
*
|
|
* SignCert() hands the buffer to AddSignature(), which appends the
|
|
* signatureAlgorithm AlgorithmIdentifier and the signatureValue BIT STRING as
|
|
* well as wrapping everything in the outer SEQUENCE. A size check that only
|
|
* accounts for sequence headers under-counts by the algorithm identifier and
|
|
* bit string header, so capacities in a narrow band just below the exact
|
|
* encoding size get accepted and overrun.
|
|
*/
|
|
#if !defined(NO_ASN) && !defined(NO_RSA) && !defined(NO_CERTS) && \
|
|
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \
|
|
!defined(NO_SHA256) && defined(USE_CERT_BUFFERS_2048) && \
|
|
!defined(NO_ASN_TIME) && !defined(WC_NO_RNG) && !defined(NO_ASN_CRYPT)
|
|
#define TEST_KEYUSAGE_DECIPHER_ONLY
|
|
#endif
|
|
|
|
/*
|
|
* decipherOnly is bit 8, the only KeyUsage value landing in the second byte
|
|
* of the BIT STRING - so the only one needing a second content byte to encode
|
|
* and the high-byte shift to decode. Round-trip it alone and combined with a
|
|
* first-byte bit to cover both halves.
|
|
*/
|
|
int test_wc_DecodeKeyUsage_decipherOnly(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_KEYUSAGE_DECIPHER_ONLY
|
|
static const struct {
|
|
const char* str;
|
|
word16 expected;
|
|
} kuCases[] = {
|
|
{ "decipherOnly", KEYUSE_DECIPHER_ONLY },
|
|
{ "digitalSignature,decipherOnly", (word16)(KEYUSE_DIGITAL_SIG |
|
|
KEYUSE_DECIPHER_ONLY) },
|
|
{ "encipherOnly,decipherOnly", (word16)(KEYUSE_ENCIPHER_ONLY |
|
|
KEYUSE_DECIPHER_ONLY) },
|
|
/* A first-byte-only value must keep encoding in a single byte. */
|
|
{ "digitalSignature", KEYUSE_DIGITAL_SIG },
|
|
};
|
|
WC_RNG rng;
|
|
RsaKey key;
|
|
byte* der = NULL;
|
|
word32 idx = 0;
|
|
int rngInit = 0;
|
|
int keyInit = 0;
|
|
size_t c;
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
if (EXPECT_SUCCESS()) rngInit = 1;
|
|
|
|
ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key,
|
|
sizeof_server_key_der_2048), 0);
|
|
|
|
for (c = 0; c < XELEM_CNT(kuCases); c++) {
|
|
Cert cert;
|
|
DecodedCert dCert;
|
|
int dCertInit = 0;
|
|
int derSz = 0;
|
|
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
XMEMSET(&cert, 0, sizeof(cert));
|
|
ExpectIntEQ(wc_InitCert(&cert), 0);
|
|
if (EXPECT_SUCCESS()) {
|
|
cert.sigType = CTC_SHA256wRSA;
|
|
cert.isCA = 0;
|
|
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.commonName, "keyUsage", CTC_NAME_SIZE);
|
|
}
|
|
ExpectIntEQ(wc_SetKeyUsage(&cert, kuCases[c].str), 0);
|
|
ExpectIntGT(derSz = wc_MakeSelfCert(&cert, der, FOURK_BUF, &key, &rng),
|
|
0);
|
|
|
|
if (EXPECT_SUCCESS() && (der != NULL)) {
|
|
wc_InitDecodedCert(&dCert, der, (word32)derSz, HEAP_HINT);
|
|
dCertInit = 1;
|
|
ExpectIntEQ(wc_ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
/* Every requested bit must survive and nothing else be set - a
|
|
* byte-order slip silently yields a first-byte usage. */
|
|
ExpectIntEQ(dCert.extKeyUsage, kuCases[c].expected);
|
|
}
|
|
if (dCertInit) wc_FreeDecodedCert(&dCert);
|
|
}
|
|
|
|
if (keyInit) wc_FreeRsaKey(&key);
|
|
if (rngInit) wc_FreeRng(&rng);
|
|
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif /* TEST_KEYUSAGE_DECIPHER_ONLY */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(WOLFSSL_WOLFSSH) && !defined(NO_ASN) && !defined(NO_CERTS) && \
|
|
defined(HAVE_ECC) && !defined(NO_ECC256) && !defined(NO_SHA256)
|
|
#define TEST_EXTKEYUSAGE_SSH
|
|
#endif
|
|
|
|
/*
|
|
* id-kp-secureShellClient and id-kp-secureShellServer (RFC 6187) are decoded
|
|
* into extExtKeyUsageSsh, not extExtKeyUsage. Parse a self-signed P-256 cert
|
|
* whose only key purposes are those two and check both bits land.
|
|
*/
|
|
int test_wc_DecodeExtKeyUsage_ssh(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_EXTKEYUSAGE_SSH
|
|
static const unsigned char sshEkuCert[] = {
|
|
0x30, 0x82, 0x01, 0x89, 0x30, 0x82, 0x01, 0x2f, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x09, 0x00, 0xc3, 0xf3, 0x13, 0xd2, 0x5f, 0x80, 0x6d, 0xd6,
|
|
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
|
|
0x30, 0x31, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
|
0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
|
0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x10, 0x30,
|
|
0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x73, 0x73, 0x68, 0x2d,
|
|
0x65, 0x6b, 0x75, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x39, 0x30,
|
|
0x33, 0x30, 0x34, 0x35, 0x34, 0x34, 0x36, 0x5a, 0x18, 0x0f, 0x32, 0x31,
|
|
0x32, 0x36, 0x30, 0x38, 0x31, 0x30, 0x30, 0x34, 0x35, 0x34, 0x34, 0x36,
|
|
0x5a, 0x30, 0x31, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
|
|
0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
|
|
0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x10,
|
|
0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x73, 0x73, 0x68,
|
|
0x2d, 0x65, 0x6b, 0x75, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
|
|
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
|
0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xfe, 0x1b, 0x76, 0x35, 0xdc,
|
|
0x20, 0x18, 0xc2, 0x9c, 0x30, 0x2f, 0xa7, 0x69, 0x7c, 0x9b, 0xe6, 0x9a,
|
|
0x70, 0x8f, 0x90, 0x20, 0xa2, 0xbb, 0xbe, 0xa4, 0xef, 0x46, 0xba, 0x87,
|
|
0x96, 0xfd, 0xfd, 0x93, 0xee, 0xf5, 0x9f, 0xc9, 0x89, 0x91, 0xaf, 0xf8,
|
|
0xa5, 0xd3, 0x00, 0xad, 0x27, 0xc3, 0x65, 0x0d, 0xe2, 0xc3, 0x62, 0x62,
|
|
0x9a, 0x31, 0x85, 0x5c, 0xa2, 0xcf, 0x18, 0x4d, 0xd9, 0x03, 0x65, 0xa3,
|
|
0x2e, 0x30, 0x2c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
|
|
0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x15,
|
|
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x16, 0x30, 0x0b,
|
|
0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30,
|
|
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
|
|
0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x09, 0x48, 0xa1, 0x88, 0x7e, 0x11,
|
|
0xa4, 0x70, 0x95, 0x79, 0x4b, 0x61, 0x8f, 0x37, 0xd8, 0x21, 0xa4, 0xe0,
|
|
0x4c, 0x63, 0xe6, 0x5e, 0xc2, 0x7b, 0x90, 0x5e, 0xc0, 0x7f, 0xee, 0x72,
|
|
0x76, 0x1b, 0x02, 0x21, 0x00, 0xad, 0x2b, 0x74, 0x14, 0xc4, 0x57, 0xbc,
|
|
0xbe, 0x46, 0x6b, 0x7f, 0x25, 0x90, 0x79, 0xe0, 0x82, 0xbb, 0x69, 0x43,
|
|
0x0b, 0x99, 0xbd, 0x75, 0xd3, 0x4d, 0x8c, 0x8d, 0x2c, 0x9e, 0x50, 0x69,
|
|
0x9e
|
|
};
|
|
DecodedCert cert;
|
|
|
|
wc_InitDecodedCert(&cert, sshEkuCert, (word32)sizeof(sshEkuCert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectIntEQ(cert.extExtKeyUsageSet, 1);
|
|
ExpectIntEQ(cert.extExtKeyUsage, 0);
|
|
ExpectIntEQ(cert.extExtKeyUsageSsh,
|
|
EXTKEYUSE_SSH_CLIENT_AUTH | EXTKEYUSE_SSH_SERVER_AUTH);
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif /* TEST_EXTKEYUSAGE_SSH */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* The OID sum used to identify a KeyPurposeId is a checksum and can collide.
|
|
* With the default sum, appending the arc 16256 (encoded as ff 00) to an
|
|
* 8 byte OID leaves the sum unchanged, so 1.3.6.1.5.5.7.3.22.16256 sums the
|
|
* same as id-kp-secureShellServer and 1.3.6.1.5.5.7.3.1.16256 the same as
|
|
* id-kp-serverAuth. With WOLFSSL_OLD_OID_SUM (a byte sum) swapping the last
|
|
* two arcs does the same: 1.3.6.1.5.5.7.22.3 and 1.3.6.1.5.5.7.1.3.
|
|
* Parse a self-signed P-256 cert with key purposes id-kp-secureShellClient
|
|
* plus those four colliding OIDs and check that only the byte-exact OID sets
|
|
* a bit.
|
|
*/
|
|
int test_wc_DecodeExtKeyUsage_ssh_oid_collision(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_EXTKEYUSAGE_SSH
|
|
static const unsigned char sshEkuCollideCert[] = {
|
|
0x30, 0x82, 0x01, 0xb9, 0x30, 0x82, 0x01, 0x60, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x08, 0x7f, 0x1c, 0x2e, 0x3d, 0x4a, 0x5b, 0x6c, 0x7d, 0x30,
|
|
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
|
|
0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
|
|
0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
|
|
0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x18, 0x30, 0x16,
|
|
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x73, 0x68, 0x2d, 0x65,
|
|
0x6b, 0x75, 0x2d, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x30, 0x20,
|
|
0x17, 0x0d, 0x32, 0x36, 0x30, 0x39, 0x30, 0x33, 0x31, 0x39, 0x33, 0x37,
|
|
0x32, 0x33, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, 0x36, 0x30, 0x38, 0x31,
|
|
0x30, 0x31, 0x39, 0x33, 0x37, 0x32, 0x33, 0x5a, 0x30, 0x39, 0x31, 0x0b,
|
|
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
|
|
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f,
|
|
0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
|
|
0x04, 0x03, 0x0c, 0x0f, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x6b, 0x75, 0x2d,
|
|
0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06,
|
|
0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86,
|
|
0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x68, 0xa5,
|
|
0x0e, 0x32, 0xbe, 0x32, 0xad, 0xad, 0xe9, 0x6a, 0xdb, 0x42, 0x0a, 0x96,
|
|
0xfc, 0xaa, 0xd6, 0x5c, 0xe2, 0x40, 0x5f, 0x39, 0xfb, 0xc9, 0xce, 0x4a,
|
|
0xfe, 0xe0, 0xe8, 0xae, 0x12, 0x9b, 0x1d, 0x56, 0x0c, 0x88, 0x30, 0x7f,
|
|
0x8a, 0x7f, 0xd7, 0x94, 0x54, 0x76, 0x9f, 0x73, 0x5c, 0x0f, 0x37, 0x06,
|
|
0x66, 0xab, 0xfa, 0xf7, 0x71, 0x3a, 0x11, 0x86, 0x58, 0x3b, 0x85, 0x12,
|
|
0x5f, 0x3d, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x3f, 0x06, 0x03, 0x55, 0x1d,
|
|
0x25, 0x04, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
|
|
0x07, 0x03, 0x15, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
|
|
0x16, 0xff, 0x00, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x16,
|
|
0x03, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0xff,
|
|
0x00, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x03, 0x30,
|
|
0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
|
|
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
|
|
0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x01, 0xab, 0x08, 0xf9, 0xf0,
|
|
0xe5, 0x0e, 0x47, 0x1e, 0x68, 0xb8, 0xce, 0x16, 0x94, 0x2f, 0x8f, 0xfc,
|
|
0x6c, 0x95, 0x32, 0xd0, 0x5d, 0x60, 0x54, 0x18, 0xf5, 0x84, 0x67, 0x4f,
|
|
0x0c, 0xbd, 0x93, 0x02, 0x20, 0x1c, 0x29, 0x80, 0x00, 0x6f, 0xf6, 0x19,
|
|
0x66, 0x25, 0x35, 0x81, 0x38, 0x91, 0x6e, 0xb9, 0xaa, 0x80, 0xb8, 0x7a,
|
|
0x3b, 0xab, 0x20, 0x89, 0x1d, 0x04, 0x05, 0x53, 0xa0, 0x5e, 0xf2, 0xe6,
|
|
0xa9
|
|
};
|
|
DecodedCert cert;
|
|
|
|
wc_InitDecodedCert(&cert, sshEkuCollideCert,
|
|
(word32)sizeof(sshEkuCollideCert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectIntEQ(cert.extExtKeyUsageSet, 1);
|
|
/* 1.3.6.1.5.5.7.3.1.16256 and 1.3.6.1.5.5.7.1.3 must not be taken for
|
|
* id-kp-serverAuth. */
|
|
ExpectIntEQ(cert.extExtKeyUsage, 0);
|
|
/* 1.3.6.1.5.5.7.3.22.16256 and 1.3.6.1.5.5.7.22.3 must not be taken for
|
|
* id-kp-secureShellServer. */
|
|
ExpectIntEQ(cert.extExtKeyUsageSsh, EXTKEYUSE_SSH_CLIENT_AUTH);
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif /* TEST_EXTKEYUSAGE_SSH */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if !defined(NO_ASN) && !defined(NO_RSA) && !defined(NO_CERTS) && \
|
|
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \
|
|
defined(WOLFSSL_EKU_OID) && !defined(NO_SHA256) && \
|
|
defined(USE_CERT_BUFFERS_2048) && !defined(NO_ASN_TIME) && \
|
|
!defined(WC_NO_RNG) && !defined(NO_ASN_CRYPT)
|
|
#define TEST_EKU_OID_SUM_COLLISION
|
|
#endif
|
|
|
|
/* A KeyPurposeId whose wc_oid_sum() collides with id-kp-serverAuth must not
|
|
* authorize server authentication, while the real OID still does. */
|
|
int test_wc_DecodeExtKeyUsage_oidSumCollision(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_EKU_OID_SUM_COLLISION
|
|
static const struct {
|
|
const char* oid; /* custom EKU OID, NULL to use a named purpose */
|
|
const char* name; /* named purpose, used when oid is NULL */
|
|
byte expected;
|
|
} ekuCases[] = {
|
|
/* id-kp-serverAuth. */
|
|
{ NULL, "serverAuth", EXTKEYUSE_SERVER_AUTH },
|
|
#ifdef WOLFSSL_OLD_OID_SUM
|
|
/* 1.5.6.1.5.5.3.1, the same byte sum (71) as id-kp-serverAuth. */
|
|
{ "1.5.6.1.5.5.3.1", NULL, 0 },
|
|
#else
|
|
/* 1.19.6.1.5.21.7.3.1, the same XOR-shift sum (0x0402012e) as
|
|
* id-kp-serverAuth. */
|
|
{ "1.19.6.1.5.21.7.3.1", NULL, 0 },
|
|
#endif
|
|
};
|
|
WC_RNG rng;
|
|
RsaKey key;
|
|
byte* der = NULL;
|
|
word32 idx = 0;
|
|
int rngInit = 0;
|
|
int keyInit = 0;
|
|
size_t c;
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
if (EXPECT_SUCCESS()) rngInit = 1;
|
|
|
|
ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key,
|
|
sizeof_server_key_der_2048), 0);
|
|
|
|
for (c = 0; c < XELEM_CNT(ekuCases); c++) {
|
|
Cert cert;
|
|
DecodedCert dCert;
|
|
int dCertInit = 0;
|
|
int derSz = 0;
|
|
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
XMEMSET(&cert, 0, sizeof(cert));
|
|
ExpectIntEQ(wc_InitCert(&cert), 0);
|
|
if (EXPECT_SUCCESS()) {
|
|
cert.sigType = CTC_SHA256wRSA;
|
|
cert.isCA = 0;
|
|
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.commonName, "extKeyUsage", CTC_NAME_SIZE);
|
|
}
|
|
if (ekuCases[c].oid != NULL) {
|
|
ExpectIntEQ(wc_SetExtKeyUsageOID(&cert, ekuCases[c].oid,
|
|
(word32)XSTRLEN(ekuCases[c].oid), 0, HEAP_HINT), 0);
|
|
}
|
|
else {
|
|
ExpectIntEQ(wc_SetExtKeyUsage(&cert, ekuCases[c].name), 0);
|
|
}
|
|
ExpectIntGT(derSz = wc_MakeSelfCert(&cert, der, FOURK_BUF, &key, &rng),
|
|
0);
|
|
|
|
if (EXPECT_SUCCESS() && (der != NULL)) {
|
|
wc_InitDecodedCert(&dCert, der, (word32)derSz, HEAP_HINT);
|
|
dCertInit = 1;
|
|
ExpectIntEQ(wc_ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
/* The extension must be seen in both cases - an unrecognized
|
|
* KeyPurposeId is skipped, not an error - but only the real OID
|
|
* may authorize a purpose. */
|
|
ExpectIntNE(dCert.extExtKeyUsageSet, 0);
|
|
ExpectIntEQ(dCert.extExtKeyUsage, ekuCases[c].expected);
|
|
}
|
|
if (dCertInit) wc_FreeDecodedCert(&dCert);
|
|
}
|
|
|
|
if (keyInit) wc_FreeRsaKey(&key);
|
|
if (rngInit) wc_FreeRng(&rng);
|
|
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#endif /* TEST_EKU_OID_SUM_COLLISION */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
int test_wc_SignCert_buffer_bounds(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(TEST_SIGN_CERT_BOUNDS_RSA) || defined(TEST_SIGN_CERT_BOUNDS_ECC)
|
|
WC_RNG rng;
|
|
Cert cert;
|
|
byte* scratch = NULL;
|
|
byte* buf = NULL;
|
|
int rngInit = 0;
|
|
int bodySz = 0;
|
|
int cap;
|
|
int i;
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
RsaKey key;
|
|
word32 idx = 0;
|
|
int keyInit = 0;
|
|
int exactSz = 0;
|
|
#endif
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_ECC
|
|
ecc_key eccKey;
|
|
word32 eccIdx = 0;
|
|
int eccInit = 0;
|
|
int eccExactSz = 0;
|
|
int eccSignedSz = 0;
|
|
int k;
|
|
#endif
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
XMEMSET(&cert, 0, sizeof(cert));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
if (EXPECT_SUCCESS()) rngInit = 1;
|
|
|
|
ExpectNotNull(scratch = (byte*)XMALLOC(SIGN_CERT_SCRATCH_SZ, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
ExpectNotNull(buf = (byte*)XMALLOC(SIGN_CERT_SCRATCH_SZ, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key,
|
|
sizeof_server_key_der_2048), 0);
|
|
|
|
/* Sign into a roomy buffer once to learn the exact encoding size. */
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBody(&cert, &key, &rng, scratch,
|
|
SIGN_CERT_SCRATCH_SZ), 0);
|
|
ExpectIntGT(exactSz = wc_SignCert(bodySz, cert.sigType, scratch,
|
|
SIGN_CERT_SCRATCH_SZ, &key, NULL, &rng), 0);
|
|
ExpectIntLT(exactSz + SIGN_CERT_GUARD_SZ, SIGN_CERT_SCRATCH_SZ);
|
|
|
|
/* Every capacity below the exact size has to be rejected, and rejected
|
|
* without touching a byte beyond it. */
|
|
for (cap = exactSz - SIGN_CERT_BAND_SZ; cap < exactSz; cap++) {
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBody(&cert, &key, &rng,
|
|
scratch, SIGN_CERT_SCRATCH_SZ), 0);
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
XMEMCPY(buf, scratch, (size_t)bodySz);
|
|
XMEMSET(buf + cap, SIGN_CERT_GUARD_BYTE, SIGN_CERT_GUARD_SZ);
|
|
|
|
ExpectIntEQ(wc_SignCert(bodySz, cert.sigType, buf, (word32)cap, &key,
|
|
NULL, &rng), WC_NO_ERR_TRACE(BUFFER_E));
|
|
|
|
for (i = 0; i < SIGN_CERT_GUARD_SZ; i++) {
|
|
ExpectIntEQ(buf[cap + i], SIGN_CERT_GUARD_BYTE);
|
|
}
|
|
}
|
|
|
|
/* The exact size still has to be accepted - the check must not be made
|
|
* conservative instead of correct. */
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBody(&cert, &key, &rng, scratch,
|
|
SIGN_CERT_SCRATCH_SZ), 0);
|
|
if (EXPECT_SUCCESS() && (buf != NULL)) {
|
|
XMEMCPY(buf, scratch, (size_t)bodySz);
|
|
XMEMSET(buf + exactSz, SIGN_CERT_GUARD_BYTE, SIGN_CERT_GUARD_SZ);
|
|
}
|
|
ExpectIntEQ(wc_SignCert(bodySz, cert.sigType, buf, (word32)exactSz, &key,
|
|
NULL, &rng), exactSz);
|
|
for (i = 0; i < SIGN_CERT_GUARD_SZ; i++) {
|
|
ExpectIntEQ(buf[exactSz + i], SIGN_CERT_GUARD_BYTE);
|
|
}
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA */
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_ECC
|
|
/* Same sweep for ECDSA. IsSigAlgoNoParams() drops the NULL parameters from
|
|
* the AlgorithmIdentifier, so the under-count an estimate makes has a
|
|
* different width here than it does for RSA. */
|
|
XMEMSET(&eccKey, 0, sizeof(eccKey));
|
|
ExpectIntEQ(wc_ecc_init_ex(&eccKey, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) eccInit = 1;
|
|
ExpectIntEQ(wc_EccPrivateKeyDecode(ecc_key_der_256, &eccIdx, &eccKey,
|
|
sizeof_ecc_key_der_256), 0);
|
|
|
|
for (k = 1; k < SIGN_CERT_BAND_SZ; k++) {
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
/* Measured fresh every iteration: the previous signature's length
|
|
* says nothing about the next one's. */
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBodyEcc(&cert, &eccKey, &rng,
|
|
scratch, SIGN_CERT_SCRATCH_SZ), 0);
|
|
ExpectIntGT(eccExactSz = wc_SignCert(bodySz, cert.sigType, scratch,
|
|
SIGN_CERT_SCRATCH_SZ, NULL, &eccKey, &rng), 0);
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
cap = eccExactSz - k;
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBodyEcc(&cert, &eccKey, &rng,
|
|
scratch, SIGN_CERT_SCRATCH_SZ), 0);
|
|
if (!EXPECT_SUCCESS()) break;
|
|
|
|
XMEMCPY(buf, scratch, (size_t)bodySz);
|
|
XMEMSET(buf + cap, SIGN_CERT_GUARD_BYTE, SIGN_CERT_GUARD_SZ);
|
|
|
|
eccSignedSz = wc_SignCert(bodySz, cert.sigType, buf, (word32)cap, NULL,
|
|
&eccKey, &rng);
|
|
/* The signature this call produces is not the one the capacity was
|
|
* derived from, so a capacity below the measured size is not always
|
|
* too small. Both outcomes are legitimate; what must hold either way
|
|
* is that nothing was written past the capacity. */
|
|
ExpectTrue((eccSignedSz == WC_NO_ERR_TRACE(BUFFER_E)) ||
|
|
((eccSignedSz > 0) && (eccSignedSz <= cap)));
|
|
|
|
for (i = 0; i < SIGN_CERT_GUARD_SZ; i++) {
|
|
ExpectIntEQ(buf[cap + i], SIGN_CERT_GUARD_BYTE);
|
|
}
|
|
}
|
|
|
|
/* A capacity above anything the signature length can reach still has to be
|
|
* accepted, so the check is not merely conservative. */
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBodyEcc(&cert, &eccKey, &rng,
|
|
scratch, SIGN_CERT_SCRATCH_SZ), 0);
|
|
ExpectIntGT(eccExactSz = wc_SignCert(bodySz, cert.sigType, scratch,
|
|
SIGN_CERT_SCRATCH_SZ, NULL, &eccKey, &rng), 0);
|
|
cap = eccExactSz + SIGN_CERT_ECC_SLACK;
|
|
ExpectIntGT(bodySz = test_wc_SignCert_makeBodyEcc(&cert, &eccKey, &rng,
|
|
scratch, SIGN_CERT_SCRATCH_SZ), 0);
|
|
if (EXPECT_SUCCESS() && (buf != NULL)) {
|
|
XMEMCPY(buf, scratch, (size_t)bodySz);
|
|
XMEMSET(buf + cap, SIGN_CERT_GUARD_BYTE, SIGN_CERT_GUARD_SZ);
|
|
}
|
|
ExpectIntGT(eccSignedSz = wc_SignCert(bodySz, cert.sigType, buf,
|
|
(word32)cap, NULL, &eccKey, &rng), 0);
|
|
ExpectIntLE(eccSignedSz, cap);
|
|
for (i = 0; i < SIGN_CERT_GUARD_SZ; i++) {
|
|
ExpectIntEQ(buf[cap + i], SIGN_CERT_GUARD_BYTE);
|
|
}
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_ECC */
|
|
|
|
XFREE(buf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
XFREE(scratch, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_ECC
|
|
if (eccInit)
|
|
wc_ecc_free(&eccKey);
|
|
#endif
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
if (keyInit)
|
|
wc_FreeRsaKey(&key);
|
|
#endif
|
|
if (rngInit)
|
|
wc_FreeRng(&rng);
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA || TEST_SIGN_CERT_BOUNDS_ECC */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
/* Scan a DER certificate body for a well-formed validity time TLV of the
|
|
* given tag. UTCTime is "YYMMDDHHMMSSZ" (13 content bytes), GeneralizedTime
|
|
* is "YYYYMMDDHHMMSSZ" (15). Both are emitted by SetTime() with the Zulu
|
|
* profile, so the shape is exact and a match cannot be a coincidental byte
|
|
* pair inside a key or signature. Returns 1 when found, 0 otherwise. */
|
|
static int test_asn_findValidityTime(const byte* der, word32 derSz, byte tag,
|
|
byte contentSz)
|
|
{
|
|
word32 i, j;
|
|
|
|
if (der == NULL || derSz < (word32)contentSz + 2U)
|
|
return 0;
|
|
|
|
for (i = 0; i + 2U + contentSz <= derSz; i++) {
|
|
if (der[i] != tag || der[i + 1] != contentSz)
|
|
continue;
|
|
for (j = 0; j < (word32)contentSz - 1U; j++) {
|
|
if (der[i + 2 + j] < '0' || der[i + 2 + j] > '9')
|
|
break;
|
|
}
|
|
if (j == (word32)contentSz - 1U &&
|
|
der[i + 2 + j] == 'Z') {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA */
|
|
|
|
/*
|
|
* RFC 5280 4.1.2.5 splits the validity encoding at the year 2050: dates
|
|
* through 2049 are UTCTime, 2050 and later are GeneralizedTime. Every
|
|
* certificate the suite builds elsewhere keeps the wc_InitCert() default
|
|
* validity, so notBefore and notAfter both land inside the UTCTime window and
|
|
* the GeneralizedTime arm of ValidityTimeFormat() is never taken.
|
|
*
|
|
* Push notAfter alone past the split with a long daysValid. One certificate
|
|
* then carries both formats - a UTCTime notBefore and a GeneralizedTime
|
|
* notAfter - which is also the shape a parser is most likely to get wrong,
|
|
* since the two fields of the same SEQUENCE no longer share a tag or a
|
|
* length.
|
|
*/
|
|
int test_wc_MakeCert_generalizedTimeValidity(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
WC_RNG rng;
|
|
Cert cert;
|
|
RsaKey key;
|
|
byte* der = NULL;
|
|
word32 idx = 0;
|
|
int rngInit = 0;
|
|
int keyInit = 0;
|
|
int derSz = 0;
|
|
static const byte serial[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08 };
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
XMEMSET(&cert, 0, sizeof(cert));
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
if (EXPECT_SUCCESS()) rngInit = 1;
|
|
|
|
ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key,
|
|
sizeof_server_key_der_2048), 0);
|
|
|
|
ExpectNotNull(der = (byte*)XMALLOC(SIGN_CERT_SCRATCH_SZ, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
ExpectIntEQ(wc_InitCert(&cert), 0);
|
|
if (EXPECT_SUCCESS()) {
|
|
cert.sigType = CTC_SHA256wRSA;
|
|
cert.isCA = 0;
|
|
XMEMCPY(cert.serial, serial, sizeof(serial));
|
|
cert.serialSz = (int)sizeof(serial);
|
|
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert.subject.commonName, "gentime-validity", CTC_NAME_SIZE);
|
|
/* ~54 years: notBefore stays in the UTCTime window, notAfter does
|
|
* not. Deliberately not a round century so the encoder has to carry
|
|
* the year across the 2050 boundary rather than sit on it. */
|
|
cert.daysValid = 20000;
|
|
}
|
|
|
|
ExpectIntGT(derSz = wc_MakeCert(&cert, der, SIGN_CERT_SCRATCH_SZ, &key,
|
|
NULL, &rng), 0);
|
|
|
|
/* notBefore is still a UTCTime and notAfter is now a GeneralizedTime, so
|
|
* both format arms ran while encoding this one certificate. */
|
|
ExpectIntEQ(test_asn_findValidityTime(der, (word32)((derSz > 0) ? derSz : 0),
|
|
ASN_UTC_TIME, 13), 1);
|
|
ExpectIntEQ(test_asn_findValidityTime(der, (word32)((derSz > 0) ? derSz : 0),
|
|
ASN_GENERALIZED_TIME, 15), 1);
|
|
|
|
/* ValidityTimeFormat() is `tm_year >= 1950 && tm_year < 2050`: the call
|
|
* above pairs the upper bound (>= 1950 held true, < 2050 flips false).
|
|
* Pair the lower bound the same way - push notAfter's year below 1950
|
|
* (~80 years back from "now") so `tm_year >= 1950` itself flips false.
|
|
* That operand is short-circuited, so the encode still lands on
|
|
* GeneralizedTime, just via the other half of the decision. wc_MakeCert()
|
|
* has no lower bound on daysValid; not asserting its return keeps a
|
|
* platform-dependent pre-epoch gmtime() failure from failing the whole
|
|
* variant. */
|
|
if (EXPECT_SUCCESS()) {
|
|
cert.daysValid = -29200;
|
|
derSz = wc_MakeCert(&cert, der, SIGN_CERT_SCRATCH_SZ, &key, NULL,
|
|
&rng);
|
|
if (derSz > 0) {
|
|
ExpectIntEQ(test_asn_findValidityTime(der, (word32)derSz,
|
|
ASN_GENERALIZED_TIME, 15), 1);
|
|
}
|
|
}
|
|
|
|
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (keyInit)
|
|
wc_FreeRsaKey(&key);
|
|
if (rngInit)
|
|
wc_FreeRng(&rng);
|
|
#endif /* TEST_SIGN_CERT_BOUNDS_RSA */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(TEST_SIGN_CERT_BOUNDS_RSA) || defined(TEST_SIGN_CERT_BOUNDS_ECC)
|
|
#define TEST_MAKECERT_SERIAL
|
|
#endif
|
|
|
|
#ifdef TEST_MAKECERT_SERIAL
|
|
/* Longest serialNumber TLV the cases below expect. */
|
|
#define TEST_SERIAL_TLV_MAX 8
|
|
|
|
/* Find the serialNumber TLV in a certificate body. wc_MakeCert() writes a
|
|
* TBSCertificate, so the [0] EXPLICIT version precedes the serial. */
|
|
static const byte* test_cert_serial_tlv(const byte* body, int bodySz)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; ((i + 5 + TEST_SERIAL_TLV_MAX) <= bodySz) && (i < 16); i++) {
|
|
if ((body[i] == 0xA0) && (body[i + 1] == 0x03) &&
|
|
(body[i + 2] == ASN_INTEGER) && (body[i + 3] == 0x01) &&
|
|
(body[i + 5] == ASN_INTEGER)) {
|
|
return &body[i + 5];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Build a certificate body carrying the given serial. */
|
|
static int test_cert_make_serial(Cert* cert, WC_RNG* rng, void* key,
|
|
byte* out, word32 outSz, const byte* serial, int serialSz)
|
|
{
|
|
int ret;
|
|
int copySz = serialSz;
|
|
|
|
/* The caller scans this buffer once the call returns, so leave it in a
|
|
* known state on the paths that bail out before the generator writes. */
|
|
XMEMSET(out, 0, outSz);
|
|
|
|
ret = wc_InitCert(cert);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
/* Keep the copy inside cert->serial so an over-long size can still be
|
|
* handed to the generator to exercise its bound check. */
|
|
if (copySz > CTC_SERIAL_SIZE)
|
|
copySz = CTC_SERIAL_SIZE;
|
|
if (copySz < 0)
|
|
copySz = 0;
|
|
|
|
cert->isCA = 0;
|
|
XMEMCPY(cert->serial, serial, (size_t)copySz);
|
|
cert->serialSz = serialSz;
|
|
XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE);
|
|
XSTRNCPY(cert->subject.commonName, "serial-encoding", CTC_NAME_SIZE);
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
cert->sigType = CTC_SHA256wRSA;
|
|
return wc_MakeCert(cert, out, outSz, (RsaKey*)key, NULL, rng);
|
|
#else
|
|
cert->sigType = CTC_SHA256wECDSA;
|
|
return wc_MakeCert(cert, out, outSz, NULL, (ecc_key*)key, rng);
|
|
#endif
|
|
}
|
|
#endif /* TEST_MAKECERT_SERIAL */
|
|
|
|
/*
|
|
* A caller-supplied serial number must be encoded as a minimal DER INTEGER.
|
|
*
|
|
* A fixed-width device serial carries leading zero bytes that DER does not
|
|
* allow, and the encoder only ever adds the sign pad, so those bytes used to
|
|
* reach the certificate untouched. The result failed to parse, here and in
|
|
* every other strict decoder.
|
|
*/
|
|
int test_wc_MakeCert_serial_encoding(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifdef TEST_MAKECERT_SERIAL
|
|
static const struct {
|
|
byte serial[CTC_SERIAL_SIZE];
|
|
int serialSz;
|
|
byte expect[TEST_SERIAL_TLV_MAX];
|
|
int expectSz;
|
|
} cases[] = {
|
|
/* Redundant leading zeros are dropped. */
|
|
{ { 0x00, 0x00, 0x00, 0x01 }, 4, { 0x02, 0x01, 0x01 }, 3 },
|
|
{ { 0x00, 0x00, 0x12, 0x34 }, 4, { 0x02, 0x02, 0x12, 0x34 }, 4 },
|
|
{ { 0x00, 0x12, 0x34, 0x56 }, 4, { 0x02, 0x03, 0x12, 0x34, 0x56 }, 5 },
|
|
/* Already minimal, so left alone. */
|
|
{ { 0x12, 0x34, 0x56, 0x78 }, 4,
|
|
{ 0x02, 0x04, 0x12, 0x34, 0x56, 0x78 }, 6 },
|
|
/* A set MSB still gets the sign pad it needs. */
|
|
{ { 0x80, 0x00, 0x00, 0x01 }, 4,
|
|
{ 0x02, 0x05, 0x00, 0x80, 0x00, 0x00, 0x01 }, 7 },
|
|
/* A sign pad the caller already supplied is not doubled. */
|
|
{ { 0x00, 0x80, 0x01 }, 3, { 0x02, 0x03, 0x00, 0x80, 0x01 }, 5 }
|
|
};
|
|
static const byte zeroSerial[4] = { 0x00, 0x00, 0x00, 0x00 };
|
|
static const byte zeroTlv[3] = { 0x02, 0x01, 0x00 };
|
|
byte maxSerial[CTC_SERIAL_SIZE];
|
|
WC_RNG rng;
|
|
Cert cert;
|
|
DecodedCert decoded;
|
|
byte* body = NULL;
|
|
const byte* tlv = NULL;
|
|
int rngInit = 0;
|
|
int bodySz = 0;
|
|
int signedSz = 0;
|
|
int i;
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
RsaKey key;
|
|
word32 idx = 0;
|
|
#else
|
|
ecc_key key;
|
|
word32 idx = 0;
|
|
#endif
|
|
int keyInit = 0;
|
|
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
XMEMSET(&cert, 0, sizeof(cert));
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
if (EXPECT_SUCCESS()) rngInit = 1;
|
|
|
|
ExpectNotNull(body = (byte*)XMALLOC(SIGN_CERT_SCRATCH_SZ, HEAP_HINT,
|
|
DYNAMIC_TYPE_TMP_BUFFER));
|
|
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key,
|
|
sizeof_server_key_der_2048), 0);
|
|
#else
|
|
ExpectIntEQ(wc_ecc_init_ex(&key, HEAP_HINT, testDevId), 0);
|
|
if (EXPECT_SUCCESS()) keyInit = 1;
|
|
ExpectIntEQ(wc_EccPrivateKeyDecode(ecc_key_der_256, &idx, &key,
|
|
sizeof_ecc_key_der_256), 0);
|
|
#endif
|
|
|
|
for (i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
|
|
ExpectIntGT(bodySz = test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, cases[i].serial, cases[i].serialSz), 0);
|
|
ExpectNotNull(tlv = test_cert_serial_tlv(body, bodySz));
|
|
if (EXPECT_SUCCESS() && (tlv != NULL)) {
|
|
ExpectIntEQ(tlv[1] + 2, cases[i].expectSz);
|
|
ExpectIntEQ(XMEMCMP(tlv, cases[i].expect,
|
|
(size_t)cases[i].expectSz), 0);
|
|
}
|
|
|
|
/* What wolfSSL emits, wolfSSL has to be able to parse back. */
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
ExpectIntGT(signedSz = wc_SignCert(bodySz, cert.sigType, body,
|
|
SIGN_CERT_SCRATCH_SZ, &key, NULL, &rng), 0);
|
|
#else
|
|
ExpectIntGT(signedSz = wc_SignCert(bodySz, cert.sigType, body,
|
|
SIGN_CERT_SCRATCH_SZ, NULL, &key, &rng), 0);
|
|
#endif
|
|
if (EXPECT_SUCCESS()) {
|
|
wc_InitDecodedCert(&decoded, body, (word32)signedSz, HEAP_HINT);
|
|
ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&decoded);
|
|
}
|
|
}
|
|
|
|
#if !defined(WOLFSSL_NO_ASN_STRICT) && !defined(WOLFSSL_PYTHON) && \
|
|
!defined(WOLFSSL_ASN_ALLOW_0_SERIAL)
|
|
/* RFC 5280 4.1.2.2 needs a positive serial, so blank silicon has to fail
|
|
* at generation rather than mint a certificate nothing will accept. */
|
|
ExpectIntEQ(test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, zeroSerial, (int)sizeof(zeroSerial)),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
(void)zeroTlv;
|
|
#elif defined(WOLFSSL_ASN_TEMPLATE)
|
|
/* The permissive build still has to emit the canonical zero encoding.
|
|
* The original back end rejects zero regardless of this macro. */
|
|
ExpectIntGT(bodySz = test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, zeroSerial, (int)sizeof(zeroSerial)), 0);
|
|
ExpectNotNull(tlv = test_cert_serial_tlv(body, bodySz));
|
|
if (EXPECT_SUCCESS() && (tlv != NULL)) {
|
|
ExpectIntEQ(XMEMCMP(tlv, zeroTlv, sizeof(zeroTlv)), 0);
|
|
}
|
|
#else
|
|
(void)zeroSerial;
|
|
(void)zeroTlv;
|
|
#endif
|
|
|
|
/* Exactly CTC_SERIAL_SIZE is the largest serial that must be accepted. */
|
|
XMEMSET(maxSerial, 0x11, sizeof(maxSerial));
|
|
ExpectIntGT(bodySz = test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, maxSerial, CTC_SERIAL_SIZE), 0);
|
|
ExpectNotNull(tlv = test_cert_serial_tlv(body, bodySz));
|
|
if (EXPECT_SUCCESS() && (tlv != NULL)) {
|
|
ExpectIntEQ(tlv[1], CTC_SERIAL_SIZE);
|
|
}
|
|
|
|
#ifdef WOLFSSL_ASN_TEMPLATE
|
|
/* A 20 byte serial with the high bit set needs a sign pad, which would
|
|
* push the encoded value to 21 octets. */
|
|
XMEMSET(maxSerial, 0x11, sizeof(maxSerial));
|
|
maxSerial[0] = 0x80;
|
|
ExpectIntEQ(test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, maxSerial, CTC_SERIAL_SIZE),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
#endif
|
|
|
|
/* A negative size is rejected by both ASN back ends. */
|
|
ExpectIntEQ(test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, cases[0].serial, -1),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
#ifdef WOLFSSL_ASN_TEMPLATE
|
|
/* Over the 20 octet ceiling RFC 5280 4.1.2.2 sets. The original ASN
|
|
* back end truncates through SetSerialNumber() instead of erroring. */
|
|
ExpectIntEQ(test_cert_make_serial(&cert, &rng, &key, body,
|
|
SIGN_CERT_SCRATCH_SZ, cases[0].serial, CTC_SERIAL_SIZE + 1),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
#endif
|
|
|
|
XFREE(body, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (keyInit) {
|
|
#ifdef TEST_SIGN_CERT_BOUNDS_RSA
|
|
wc_FreeRsaKey(&key);
|
|
#else
|
|
wc_ecc_free(&key);
|
|
#endif
|
|
}
|
|
if (rngInit)
|
|
wc_FreeRng(&rng);
|
|
#endif /* TEST_MAKECERT_SERIAL */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Certificate fixtures for the parser tests below. Guarded like the tests
|
|
* that use them so builds without them do not carry unused data. */
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA)
|
|
|
|
static const byte sig_oid_base[] = {
|
|
0x30, 0x82, 0x03, 0x17, 0x30, 0x82, 0x01, 0xff, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x0a, 0x91, 0x99, 0x9c, 0xbb, 0xa9, 0x20, 0x1f, 0xcb,
|
|
0xdd, 0xcf, 0xa5, 0xf0, 0x0b, 0x46, 0xe1, 0xcb, 0x1a, 0x18, 0x52, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x10, 0x73, 0x69, 0x67, 0x6f, 0x69, 0x64, 0x2d, 0x62, 0x61,
|
|
0x73, 0x65, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32,
|
|
0x36, 0x30, 0x39, 0x30, 0x37, 0x31, 0x36, 0x34, 0x30, 0x30, 0x33, 0x5a,
|
|
0x17, 0x0d, 0x33, 0x36, 0x30, 0x39, 0x30, 0x34, 0x31, 0x36, 0x34, 0x30,
|
|
0x30, 0x33, 0x5a, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
|
|
0x04, 0x03, 0x0c, 0x10, 0x73, 0x69, 0x67, 0x6f, 0x69, 0x64, 0x2d, 0x62,
|
|
0x61, 0x73, 0x65, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22,
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
|
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
|
|
0x02, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x40, 0x98, 0x0c, 0x0b, 0xff, 0xa5,
|
|
0x4f, 0x1d, 0x7f, 0x2c, 0x1e, 0xfa, 0xa1, 0x40, 0xd8, 0xfc, 0xc6, 0x86,
|
|
0xcc, 0x42, 0x39, 0x84, 0xf1, 0xc7, 0x6a, 0x92, 0xba, 0xd9, 0x0d, 0x78,
|
|
0xa8, 0x1a, 0xcd, 0x75, 0xeb, 0xe6, 0x18, 0x49, 0x85, 0x4b, 0x5d, 0x8d,
|
|
0xb6, 0x23, 0x1d, 0xc2, 0x53, 0x47, 0x48, 0x9c, 0xce, 0x47, 0xeb, 0x18,
|
|
0x2a, 0xa1, 0x0b, 0x90, 0x4a, 0x31, 0x86, 0x0b, 0xb3, 0xf0, 0x31, 0xa5,
|
|
0xa2, 0xad, 0x98, 0x0e, 0xf3, 0xe4, 0x7f, 0x86, 0x16, 0x39, 0x1b, 0xe6,
|
|
0x1f, 0xd9, 0xdb, 0xc0, 0x3e, 0x1b, 0x4d, 0x7c, 0x5c, 0x2d, 0xd2, 0xe0,
|
|
0xdd, 0x34, 0x0c, 0x2b, 0x24, 0x49, 0x88, 0xca, 0x8d, 0x46, 0x12, 0x7a,
|
|
0xaa, 0x94, 0x0a, 0x6e, 0xaf, 0x90, 0x02, 0x5d, 0xe8, 0x42, 0xd7, 0x3d,
|
|
0x18, 0x54, 0x0a, 0x10, 0xec, 0xe1, 0x4e, 0x83, 0x3d, 0xba, 0xc6, 0x83,
|
|
0x05, 0x65, 0xd5, 0xfc, 0xfc, 0x89, 0x67, 0xae, 0x06, 0x44, 0x44, 0x19,
|
|
0xf8, 0xaa, 0x4c, 0x15, 0xbc, 0xc4, 0x62, 0x50, 0x93, 0xc8, 0xce, 0x38,
|
|
0x50, 0x20, 0x06, 0x02, 0x24, 0xd5, 0x5a, 0x39, 0xa6, 0x64, 0x1f, 0x61,
|
|
0x03, 0xba, 0x6b, 0x7e, 0xf1, 0xd0, 0x76, 0xab, 0xc1, 0xcc, 0xce, 0x6f,
|
|
0x2a, 0x6d, 0x41, 0x96, 0xe1, 0x68, 0x29, 0x83, 0x9d, 0x4e, 0xa1, 0x7e,
|
|
0xef, 0x75, 0x8a, 0xdc, 0x3a, 0x28, 0xcf, 0xd9, 0xfd, 0x9c, 0x87, 0xbe,
|
|
0x2d, 0x9b, 0x52, 0x79, 0x70, 0x0e, 0xac, 0x5d, 0x44, 0x4f, 0xb9, 0x0d,
|
|
0x61, 0x11, 0x87, 0xd4, 0xd3, 0x1f, 0x76, 0xc5, 0x5c, 0xc7, 0xa5, 0x82,
|
|
0x72, 0xa9, 0x8e, 0x40, 0xe3, 0x95, 0x21, 0xf0, 0xb6, 0x65, 0x04, 0x53,
|
|
0x28, 0x54, 0xfd, 0x41, 0x98, 0x7b, 0xe5, 0xf0, 0xf1, 0x82, 0x0a, 0x0f,
|
|
0xcb, 0xef, 0x52, 0x5c, 0x47, 0xb4, 0x84, 0x2f, 0x87, 0x02, 0x03, 0x01,
|
|
0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0e, 0x04, 0x16, 0x04, 0x14, 0x63, 0x4c, 0x6f, 0x89, 0xa0, 0x7a, 0xe5,
|
|
0x62, 0x54, 0x33, 0x14, 0x25, 0xe6, 0xa0, 0xfe, 0x87, 0xb5, 0x80, 0xc3,
|
|
0x9e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
|
|
0x80, 0x14, 0x63, 0x4c, 0x6f, 0x89, 0xa0, 0x7a, 0xe5, 0x62, 0x54, 0x33,
|
|
0x14, 0x25, 0xe6, 0xa0, 0xfe, 0x87, 0xb5, 0x80, 0xc3, 0x9e, 0x30, 0x0f,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
|
|
0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
|
0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8d,
|
|
0xf4, 0x79, 0x72, 0xc4, 0xc6, 0xae, 0x8f, 0x9a, 0x8c, 0x69, 0x06, 0x30,
|
|
0x53, 0x15, 0x47, 0x90, 0x97, 0x1d, 0x9e, 0xad, 0x38, 0xf8, 0x51, 0x34,
|
|
0x23, 0x4e, 0x9e, 0x11, 0x33, 0x6a, 0x7b, 0x51, 0xcf, 0x2f, 0x7f, 0x37,
|
|
0x85, 0xc9, 0xb4, 0x73, 0xc8, 0x2a, 0x90, 0x0e, 0x1e, 0xe7, 0xb6, 0x75,
|
|
0xf0, 0x82, 0x98, 0x02, 0x07, 0x5c, 0x8a, 0xf7, 0x19, 0x2d, 0x53, 0x09,
|
|
0x64, 0xc5, 0xbd, 0x2e, 0x3a, 0xa5, 0x28, 0x72, 0xaf, 0x2d, 0x19, 0x64,
|
|
0x3c, 0xcb, 0xe3, 0x0b, 0x49, 0xd0, 0x6e, 0x2b, 0x0a, 0xf1, 0x5e, 0xfe,
|
|
0xf4, 0xce, 0xde, 0x7d, 0xef, 0x5a, 0x53, 0xe9, 0xcb, 0x64, 0xa3, 0x90,
|
|
0x96, 0xbd, 0x0f, 0x43, 0x74, 0x68, 0x05, 0x73, 0xd4, 0xe6, 0x59, 0xca,
|
|
0x4e, 0x12, 0x7f, 0x6d, 0x78, 0x89, 0x11, 0xaf, 0xca, 0x16, 0x1c, 0x69,
|
|
0x8a, 0xed, 0xee, 0x59, 0x04, 0x9c, 0x23, 0xd1, 0x60, 0x53, 0x43, 0xb9,
|
|
0x17, 0xd4, 0x1b, 0xc3, 0x71, 0xd4, 0xd5, 0xb0, 0x8f, 0xb6, 0xf8, 0x1b,
|
|
0xd3, 0x2e, 0x7a, 0x4f, 0x04, 0xbd, 0x3d, 0xf1, 0x27, 0x31, 0xa5, 0xe5,
|
|
0xb2, 0xe5, 0x7f, 0xb0, 0x86, 0x2e, 0xdc, 0x20, 0x50, 0x1e, 0xcf, 0x3a,
|
|
0xe8, 0x84, 0xb1, 0xb3, 0x76, 0x38, 0x8b, 0xdb, 0x4c, 0x1f, 0x4b, 0x0e,
|
|
0x24, 0x7f, 0xbe, 0x2a, 0xa6, 0xde, 0xa1, 0xb4, 0x08, 0x4d, 0x28, 0x25,
|
|
0x49, 0x85, 0xfe, 0xaa, 0x4c, 0xb0, 0x88, 0x38, 0x3b, 0xeb, 0x55, 0xee,
|
|
0xfb, 0x37, 0x58, 0x45, 0xac, 0xc7, 0x3b, 0xa1, 0x18, 0xe6, 0xb5, 0xbb,
|
|
0x4c, 0x59, 0x6d, 0xb3, 0xe6, 0xf2, 0xfa, 0x14, 0x1a, 0x48, 0x52, 0x3e,
|
|
0xab, 0xe0, 0x74, 0xeb, 0x22, 0x92, 0x90, 0x0d, 0x2a, 0x03, 0x8b, 0xfd,
|
|
0x77, 0x9c, 0x2d, 0x7b, 0xb7, 0x03, 0x57, 0x39, 0xc1, 0xa7, 0x60, 0xe3,
|
|
0x7d, 0x58, 0x9d,
|
|
};
|
|
|
|
|
|
/* The same certificate with the tbs signatureAlgorithm patched to
|
|
* sha384WithRSAEncryption and the sha256 signature re-made over the
|
|
* patched encoding: the tbs and outer algorithms disagree while the
|
|
* signature is valid for the outer one. */
|
|
static const byte sig_oid_mismatch[] = {
|
|
0x30, 0x82, 0x03, 0x17, 0x30, 0x82, 0x01, 0xff, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x0a, 0x91, 0x99, 0x9c, 0xbb, 0xa9, 0x20, 0x1f, 0xcb,
|
|
0xdd, 0xcf, 0xa5, 0xf0, 0x0b, 0x46, 0xe1, 0xcb, 0x1a, 0x18, 0x52, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c,
|
|
0x05, 0x00, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x10, 0x73, 0x69, 0x67, 0x6f, 0x69, 0x64, 0x2d, 0x62, 0x61,
|
|
0x73, 0x65, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32,
|
|
0x36, 0x30, 0x39, 0x30, 0x37, 0x31, 0x36, 0x34, 0x30, 0x30, 0x33, 0x5a,
|
|
0x17, 0x0d, 0x33, 0x36, 0x30, 0x39, 0x30, 0x34, 0x31, 0x36, 0x34, 0x30,
|
|
0x30, 0x33, 0x5a, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
|
|
0x04, 0x03, 0x0c, 0x10, 0x73, 0x69, 0x67, 0x6f, 0x69, 0x64, 0x2d, 0x62,
|
|
0x61, 0x73, 0x65, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22,
|
|
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
|
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
|
|
0x02, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x40, 0x98, 0x0c, 0x0b, 0xff, 0xa5,
|
|
0x4f, 0x1d, 0x7f, 0x2c, 0x1e, 0xfa, 0xa1, 0x40, 0xd8, 0xfc, 0xc6, 0x86,
|
|
0xcc, 0x42, 0x39, 0x84, 0xf1, 0xc7, 0x6a, 0x92, 0xba, 0xd9, 0x0d, 0x78,
|
|
0xa8, 0x1a, 0xcd, 0x75, 0xeb, 0xe6, 0x18, 0x49, 0x85, 0x4b, 0x5d, 0x8d,
|
|
0xb6, 0x23, 0x1d, 0xc2, 0x53, 0x47, 0x48, 0x9c, 0xce, 0x47, 0xeb, 0x18,
|
|
0x2a, 0xa1, 0x0b, 0x90, 0x4a, 0x31, 0x86, 0x0b, 0xb3, 0xf0, 0x31, 0xa5,
|
|
0xa2, 0xad, 0x98, 0x0e, 0xf3, 0xe4, 0x7f, 0x86, 0x16, 0x39, 0x1b, 0xe6,
|
|
0x1f, 0xd9, 0xdb, 0xc0, 0x3e, 0x1b, 0x4d, 0x7c, 0x5c, 0x2d, 0xd2, 0xe0,
|
|
0xdd, 0x34, 0x0c, 0x2b, 0x24, 0x49, 0x88, 0xca, 0x8d, 0x46, 0x12, 0x7a,
|
|
0xaa, 0x94, 0x0a, 0x6e, 0xaf, 0x90, 0x02, 0x5d, 0xe8, 0x42, 0xd7, 0x3d,
|
|
0x18, 0x54, 0x0a, 0x10, 0xec, 0xe1, 0x4e, 0x83, 0x3d, 0xba, 0xc6, 0x83,
|
|
0x05, 0x65, 0xd5, 0xfc, 0xfc, 0x89, 0x67, 0xae, 0x06, 0x44, 0x44, 0x19,
|
|
0xf8, 0xaa, 0x4c, 0x15, 0xbc, 0xc4, 0x62, 0x50, 0x93, 0xc8, 0xce, 0x38,
|
|
0x50, 0x20, 0x06, 0x02, 0x24, 0xd5, 0x5a, 0x39, 0xa6, 0x64, 0x1f, 0x61,
|
|
0x03, 0xba, 0x6b, 0x7e, 0xf1, 0xd0, 0x76, 0xab, 0xc1, 0xcc, 0xce, 0x6f,
|
|
0x2a, 0x6d, 0x41, 0x96, 0xe1, 0x68, 0x29, 0x83, 0x9d, 0x4e, 0xa1, 0x7e,
|
|
0xef, 0x75, 0x8a, 0xdc, 0x3a, 0x28, 0xcf, 0xd9, 0xfd, 0x9c, 0x87, 0xbe,
|
|
0x2d, 0x9b, 0x52, 0x79, 0x70, 0x0e, 0xac, 0x5d, 0x44, 0x4f, 0xb9, 0x0d,
|
|
0x61, 0x11, 0x87, 0xd4, 0xd3, 0x1f, 0x76, 0xc5, 0x5c, 0xc7, 0xa5, 0x82,
|
|
0x72, 0xa9, 0x8e, 0x40, 0xe3, 0x95, 0x21, 0xf0, 0xb6, 0x65, 0x04, 0x53,
|
|
0x28, 0x54, 0xfd, 0x41, 0x98, 0x7b, 0xe5, 0xf0, 0xf1, 0x82, 0x0a, 0x0f,
|
|
0xcb, 0xef, 0x52, 0x5c, 0x47, 0xb4, 0x84, 0x2f, 0x87, 0x02, 0x03, 0x01,
|
|
0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0e, 0x04, 0x16, 0x04, 0x14, 0x63, 0x4c, 0x6f, 0x89, 0xa0, 0x7a, 0xe5,
|
|
0x62, 0x54, 0x33, 0x14, 0x25, 0xe6, 0xa0, 0xfe, 0x87, 0xb5, 0x80, 0xc3,
|
|
0x9e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
|
|
0x80, 0x14, 0x63, 0x4c, 0x6f, 0x89, 0xa0, 0x7a, 0xe5, 0x62, 0x54, 0x33,
|
|
0x14, 0x25, 0xe6, 0xa0, 0xfe, 0x87, 0xb5, 0x80, 0xc3, 0x9e, 0x30, 0x0f,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
|
|
0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
|
0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x54,
|
|
0xa1, 0xc7, 0xde, 0xf4, 0x09, 0x98, 0xfe, 0xcb, 0x46, 0xb8, 0x5a, 0x43,
|
|
0xf7, 0x1d, 0x0a, 0x1f, 0xa7, 0xec, 0x8d, 0x84, 0x77, 0xcf, 0x23, 0xdb,
|
|
0xa8, 0x07, 0xaa, 0x7d, 0x33, 0x3a, 0xd0, 0x07, 0x42, 0x77, 0x48, 0x6e,
|
|
0xa3, 0xf0, 0xb2, 0x4a, 0xec, 0x52, 0x7c, 0x3f, 0x92, 0xc0, 0x27, 0xde,
|
|
0x75, 0xd8, 0x72, 0xf9, 0x51, 0x57, 0x08, 0xa4, 0xde, 0x33, 0x8a, 0xf3,
|
|
0xdf, 0x35, 0x29, 0xc7, 0x23, 0xd4, 0xcf, 0x05, 0x39, 0x97, 0x3a, 0xc7,
|
|
0x28, 0xa0, 0x6b, 0x25, 0x3c, 0xe7, 0x50, 0x0d, 0xca, 0x4a, 0xd3, 0xf4,
|
|
0xe5, 0x47, 0xcd, 0xc8, 0x97, 0xbe, 0x67, 0x11, 0x5f, 0x1e, 0x43, 0xed,
|
|
0x9d, 0x95, 0x10, 0xf0, 0x43, 0x1c, 0xbd, 0x57, 0x31, 0x4b, 0x5e, 0xe9,
|
|
0x63, 0x84, 0x8b, 0xba, 0xf4, 0xfe, 0x70, 0xe6, 0xa6, 0x5f, 0x0b, 0x8f,
|
|
0x47, 0x9a, 0x72, 0x2f, 0x51, 0x91, 0x66, 0xd8, 0xa4, 0xf9, 0xcc, 0x6d,
|
|
0x14, 0xf5, 0x3b, 0xd7, 0xa3, 0xd8, 0xbf, 0xb0, 0x14, 0x9d, 0x5e, 0x14,
|
|
0x5e, 0xc1, 0x78, 0x78, 0xdc, 0xca, 0x8c, 0xc8, 0x06, 0x45, 0x06, 0x4a,
|
|
0xf0, 0x5d, 0x63, 0xa8, 0x96, 0x24, 0x44, 0xcb, 0xf4, 0x0a, 0xaa, 0x38,
|
|
0x00, 0xbd, 0xf2, 0xdc, 0xa9, 0xd0, 0x0f, 0x59, 0x74, 0xc2, 0xbe, 0x8a,
|
|
0x27, 0xe5, 0x7d, 0x3f, 0x53, 0xac, 0xcc, 0x63, 0x13, 0xe9, 0x8c, 0x7c,
|
|
0x09, 0xe3, 0x84, 0x42, 0xfe, 0xc6, 0x2b, 0x59, 0x00, 0x02, 0x6b, 0xaa,
|
|
0x32, 0x5e, 0x6a, 0x29, 0x75, 0x0d, 0x3a, 0x12, 0x5e, 0x73, 0x5b, 0x22,
|
|
0x1d, 0xaf, 0x14, 0x6e, 0x9c, 0x0a, 0x72, 0xab, 0x09, 0xc4, 0xe3, 0xb6,
|
|
0xda, 0x1d, 0xfa, 0xb8, 0x3d, 0xff, 0x41, 0x5a, 0x1c, 0x62, 0xf2, 0xdb,
|
|
0x5b, 0x9c, 0x1b, 0x25, 0xc4, 0x35, 0x55, 0xa3, 0x74, 0xec, 0x0b, 0x17,
|
|
0xc7, 0x94, 0xe6,
|
|
};
|
|
|
|
static const byte empty_san_cert[] = {
|
|
0x30, 0x82, 0x02, 0xfd, 0x30, 0x82, 0x01, 0xe5, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x79, 0x26, 0x41, 0x29, 0xa5, 0x03, 0xff, 0x71, 0x75,
|
|
0x8e, 0xdd, 0x4b, 0x0c, 0xc6, 0x77, 0xf4, 0x59, 0x01, 0x2b, 0x4f, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x19, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x0e, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2d, 0x73, 0x61, 0x6e,
|
|
0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30,
|
|
0x39, 0x30, 0x37, 0x31, 0x36, 0x33, 0x39, 0x32, 0x38, 0x5a, 0x17, 0x0d,
|
|
0x33, 0x36, 0x30, 0x39, 0x30, 0x34, 0x31, 0x36, 0x33, 0x39, 0x32, 0x38,
|
|
0x5a, 0x30, 0x19, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03,
|
|
0x0c, 0x0e, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2d, 0x73, 0x61, 0x6e, 0x2d,
|
|
0x74, 0x65, 0x73, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
|
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
|
|
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
|
|
0x00, 0xc6, 0x5a, 0xe5, 0xb3, 0x07, 0xcf, 0x1c, 0xf4, 0xe5, 0xba, 0x5a,
|
|
0xc3, 0xc9, 0x29, 0x88, 0x01, 0x48, 0xdb, 0xfd, 0xaf, 0x19, 0x8c, 0x1b,
|
|
0xaf, 0xd4, 0xf7, 0xde, 0x33, 0xd7, 0xf2, 0x13, 0x82, 0x1a, 0xe1, 0x05,
|
|
0xa7, 0x0e, 0xe6, 0x9a, 0xd2, 0x02, 0xaa, 0x01, 0x40, 0xfc, 0x33, 0x49,
|
|
0x95, 0x1c, 0xe4, 0xc5, 0x7c, 0xea, 0x42, 0x57, 0x2e, 0x33, 0x5f, 0x99,
|
|
0xb5, 0xae, 0xb2, 0xc9, 0xe0, 0xc8, 0x24, 0xdf, 0x61, 0xa5, 0x3d, 0x8d,
|
|
0x39, 0x65, 0xaa, 0x67, 0xca, 0x9e, 0x2a, 0xe2, 0x5b, 0x61, 0xe7, 0xb1,
|
|
0xea, 0x09, 0x38, 0xce, 0xfa, 0x69, 0x56, 0x00, 0x4f, 0xff, 0xb0, 0xb1,
|
|
0x98, 0x29, 0xce, 0xeb, 0x18, 0x2b, 0xcc, 0x19, 0xda, 0x47, 0xb7, 0x6e,
|
|
0xd4, 0x9a, 0xac, 0xb0, 0xb5, 0x05, 0x16, 0x03, 0xdc, 0xc4, 0x34, 0xb5,
|
|
0xb5, 0x2e, 0xd2, 0xf4, 0x50, 0xb3, 0xfb, 0xe6, 0xe1, 0xe8, 0x61, 0x62,
|
|
0xd2, 0x53, 0x85, 0x9d, 0x99, 0x09, 0xd0, 0x3b, 0xa3, 0x45, 0x59, 0x07,
|
|
0x48, 0xf8, 0x42, 0x17, 0xac, 0xcb, 0x8f, 0xed, 0x2e, 0xf3, 0x10, 0x54,
|
|
0xff, 0x6e, 0x3d, 0x86, 0x73, 0xfa, 0x4d, 0x12, 0x03, 0x58, 0x52, 0x3e,
|
|
0x54, 0xf9, 0xea, 0xa1, 0x47, 0xb3, 0x9f, 0x4c, 0x1e, 0x58, 0x78, 0x7f,
|
|
0x2b, 0xd2, 0xce, 0xd3, 0xd2, 0xb0, 0x43, 0xaf, 0x97, 0x2e, 0x66, 0xfd,
|
|
0xbb, 0x1d, 0xfa, 0x42, 0x7b, 0x78, 0xeb, 0xa0, 0x99, 0xa8, 0x79, 0xb8,
|
|
0x71, 0x19, 0x11, 0x89, 0x2c, 0x44, 0x8e, 0x2d, 0x6a, 0x1b, 0x32, 0xe3,
|
|
0xda, 0x0d, 0xb1, 0x16, 0xe4, 0x61, 0x25, 0x23, 0x74, 0x1c, 0x46, 0xb1,
|
|
0x6f, 0x67, 0x44, 0x5a, 0xf6, 0xd9, 0x9d, 0xf0, 0x95, 0x2b, 0x08, 0xb2,
|
|
0xca, 0x79, 0x45, 0x17, 0x76, 0x6c, 0xe0, 0x1c, 0x7d, 0x76, 0x52, 0x4b,
|
|
0x50, 0xb1, 0x20, 0x42, 0x2b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x3d,
|
|
0x30, 0x3b, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
|
|
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x09, 0x06, 0x03, 0x55,
|
|
0x1d, 0x11, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0e, 0x04, 0x16, 0x04, 0x14, 0x71, 0xcf, 0x04, 0xd3, 0x4b, 0x5f, 0x79,
|
|
0x6d, 0x27, 0x77, 0x48, 0x79, 0x02, 0xa5, 0xe4, 0x5b, 0x6f, 0x59, 0x94,
|
|
0xe4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
|
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x2a, 0x01, 0xee,
|
|
0x6d, 0x7d, 0xd5, 0x84, 0x17, 0x62, 0x92, 0x91, 0x51, 0x88, 0xcc, 0x41,
|
|
0xe6, 0xe2, 0x0c, 0x22, 0x73, 0xfa, 0x1a, 0x72, 0x29, 0x18, 0x13, 0x5b,
|
|
0xbd, 0x22, 0x27, 0xa7, 0x6d, 0x24, 0x01, 0x5f, 0xcf, 0x46, 0x72, 0xf5,
|
|
0x7d, 0x54, 0xf9, 0x7c, 0x0c, 0x3e, 0x38, 0xae, 0x10, 0x03, 0x28, 0x38,
|
|
0x3d, 0xb7, 0x83, 0xea, 0x93, 0xb0, 0x4b, 0x4a, 0x69, 0x7b, 0xee, 0xa3,
|
|
0x3d, 0xae, 0x86, 0xa2, 0x0a, 0xd0, 0x14, 0x91, 0x4d, 0x0e, 0x9e, 0xbd,
|
|
0xc5, 0xed, 0x69, 0xef, 0x4c, 0xf0, 0x9d, 0x9d, 0x66, 0xd8, 0xe4, 0x8f,
|
|
0x35, 0xbb, 0xef, 0xd6, 0xa4, 0x2f, 0x8f, 0xda, 0x36, 0xf4, 0xe8, 0xb9,
|
|
0xa4, 0x4d, 0x71, 0xe7, 0x38, 0xca, 0xc2, 0x41, 0x4a, 0xa6, 0x17, 0xb3,
|
|
0xa2, 0xbd, 0x2d, 0x4c, 0xd5, 0xec, 0xe7, 0xf8, 0x91, 0x9a, 0xe3, 0x01,
|
|
0x01, 0x26, 0x53, 0x19, 0xbe, 0x52, 0x57, 0xe7, 0xf3, 0xec, 0x8c, 0xed,
|
|
0xac, 0xf7, 0x6b, 0x1e, 0xbf, 0xa5, 0x52, 0x3b, 0x2d, 0x38, 0xc1, 0xce,
|
|
0x34, 0x9e, 0xad, 0x1b, 0x44, 0xe9, 0xe8, 0x57, 0x2b, 0x16, 0x9b, 0x69,
|
|
0x45, 0xda, 0xd1, 0xc9, 0x48, 0xaf, 0xa0, 0xc1, 0xfd, 0x4b, 0x0a, 0xc5,
|
|
0x8a, 0x52, 0xbf, 0x55, 0xa0, 0x99, 0x58, 0x14, 0x46, 0x89, 0x3e, 0x56,
|
|
0xe6, 0xcd, 0xec, 0xc4, 0x35, 0x24, 0x8e, 0x34, 0xfe, 0xe1, 0xbb, 0x0f,
|
|
0x76, 0x46, 0x0f, 0xdd, 0x98, 0x1f, 0x3a, 0x8e, 0x5c, 0x06, 0xee, 0x46,
|
|
0xce, 0x5a, 0x13, 0x9b, 0xee, 0x18, 0xad, 0xbf, 0x21, 0xcb, 0x53, 0x66,
|
|
0x0b, 0xbc, 0x60, 0x89, 0xf0, 0x32, 0x8e, 0x60, 0x5c, 0x69, 0x23, 0x38,
|
|
0xc7, 0xe9, 0x8d, 0xf1, 0x5e, 0xfe, 0x8b, 0x09, 0x2b, 0x9c, 0x29, 0xbe,
|
|
0x35, 0x13, 0x3f, 0x69, 0xf9, 0x40, 0xb9, 0x5b, 0xc2, 0x95, 0x8b, 0x98,
|
|
0xe8,
|
|
};
|
|
|
|
|
|
/* Offset of the subject RDN SET's length byte in mv_rdn_cert. */
|
|
#define MV_RDN_SET_LEN_IDX 151
|
|
/* Offset of the length byte of the subject RDN's first AttributeTypeAndValue
|
|
* SEQUENCE in mv_rdn_cert. */
|
|
#define MV_RDN_AVA_LEN_IDX 153
|
|
|
|
static const byte mv_rdn_cert[] = {
|
|
0x30, 0x82, 0x03, 0x61, 0x30, 0x82, 0x02, 0x49, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x15, 0xba, 0x38, 0x65, 0xcf, 0xf2, 0xa7, 0xe5, 0xa0,
|
|
0x39, 0x7e, 0x9b, 0x94, 0xdf, 0xb6, 0xf5, 0x77, 0x4a, 0x19, 0xf1, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x40, 0x31, 0x3e, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
|
0x06, 0x13, 0x02, 0x42, 0x47, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
|
0x0c, 0x0f, 0x49, 0x6e, 0x66, 0x6f, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x79,
|
|
0x20, 0x54, 0x65, 0x73, 0x74, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03,
|
|
0x0c, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x20, 0x56, 0x61, 0x6c, 0x75,
|
|
0x65, 0x20, 0x52, 0x44, 0x4e, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d,
|
|
0x32, 0x36, 0x30, 0x39, 0x30, 0x37, 0x31, 0x36, 0x33, 0x39, 0x30, 0x33,
|
|
0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x39, 0x30, 0x34, 0x31, 0x36, 0x33,
|
|
0x39, 0x30, 0x33, 0x5a, 0x30, 0x40, 0x31, 0x3e, 0x30, 0x09, 0x06, 0x03,
|
|
0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x47, 0x30, 0x16, 0x06, 0x03, 0x55,
|
|
0x04, 0x0a, 0x0c, 0x0f, 0x49, 0x6e, 0x66, 0x6f, 0x4e, 0x6f, 0x74, 0x61,
|
|
0x72, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x30, 0x19, 0x06, 0x03, 0x55,
|
|
0x04, 0x03, 0x0c, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x20, 0x56, 0x61,
|
|
0x6c, 0x75, 0x65, 0x20, 0x52, 0x44, 0x4e, 0x20, 0x43, 0x41, 0x30, 0x82,
|
|
0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
|
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
|
|
0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdd, 0xe7, 0x98, 0x94, 0xbc,
|
|
0x75, 0xfd, 0xae, 0x97, 0xaa, 0xc6, 0x6c, 0x09, 0x9f, 0x80, 0x8b, 0x6a,
|
|
0x6b, 0x6c, 0x37, 0x59, 0x19, 0x04, 0x88, 0x3d, 0xf9, 0xcf, 0x96, 0x69,
|
|
0x14, 0x79, 0xe9, 0x00, 0x99, 0x09, 0x94, 0xc1, 0xf4, 0xe1, 0xfe, 0x35,
|
|
0x23, 0xd2, 0x17, 0x09, 0x77, 0x36, 0x64, 0xda, 0x44, 0x0c, 0xb3, 0x6f,
|
|
0xb3, 0xe4, 0xbd, 0x3e, 0xba, 0x32, 0x51, 0xbd, 0xc2, 0x76, 0x00, 0x2e,
|
|
0x08, 0xfc, 0x41, 0xc6, 0xfd, 0xe8, 0x59, 0xf7, 0x04, 0x38, 0x03, 0x62,
|
|
0x07, 0xa0, 0x19, 0x7c, 0xb8, 0x7b, 0xa6, 0xc5, 0x45, 0xd8, 0x6e, 0x35,
|
|
0x50, 0xbd, 0x85, 0xf3, 0x78, 0x29, 0xb0, 0x2e, 0x77, 0x57, 0x88, 0xa0,
|
|
0x50, 0x1f, 0x1e, 0x16, 0x76, 0xfd, 0xa0, 0x83, 0xbf, 0xc9, 0xc3, 0x09,
|
|
0x7f, 0x05, 0x97, 0xa3, 0xeb, 0xeb, 0x98, 0x3e, 0x98, 0xf7, 0x39, 0x87,
|
|
0xe5, 0xd5, 0xeb, 0x0f, 0x0f, 0x1e, 0xa9, 0x3c, 0x40, 0xcd, 0xa4, 0x89,
|
|
0xa1, 0x9f, 0x14, 0x91, 0xbe, 0x97, 0x88, 0xda, 0xaf, 0xff, 0xea, 0xf5,
|
|
0xb4, 0x49, 0x87, 0xff, 0x75, 0x94, 0x61, 0x70, 0xec, 0xaa, 0x9c, 0xde,
|
|
0x70, 0xc0, 0xa1, 0x5b, 0xbb, 0x3c, 0xd5, 0x52, 0xd7, 0xea, 0x22, 0xb1,
|
|
0xe1, 0x06, 0x28, 0xc6, 0xcf, 0x8a, 0x0c, 0x6f, 0xb7, 0x94, 0x54, 0xe0,
|
|
0x42, 0x66, 0xb9, 0x37, 0x37, 0xe0, 0x86, 0x88, 0x10, 0x6f, 0xa2, 0xa5,
|
|
0x69, 0xcb, 0x25, 0x91, 0x25, 0xae, 0xae, 0x70, 0xf9, 0x6f, 0x3a, 0xe8,
|
|
0xa4, 0xf4, 0x91, 0x5b, 0xb0, 0xca, 0x54, 0xf0, 0x30, 0xc7, 0x6d, 0x88,
|
|
0x0d, 0x6a, 0x94, 0xe5, 0xd6, 0x4d, 0x30, 0xff, 0xa4, 0xd2, 0x55, 0x1a,
|
|
0xb0, 0x48, 0x73, 0xd1, 0x46, 0x02, 0x6c, 0x5a, 0x79, 0x2f, 0xb4, 0xfb,
|
|
0x01, 0x63, 0xef, 0x3c, 0xb8, 0x2e, 0x68, 0x35, 0xf5, 0x97, 0xdd, 0x02,
|
|
0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03,
|
|
0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xfc, 0x7e, 0xb4, 0x94, 0x34,
|
|
0xa8, 0x05, 0xd7, 0xac, 0x7c, 0x88, 0x5c, 0xec, 0x46, 0x3f, 0x39, 0xb5,
|
|
0x23, 0x4c, 0x32, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
|
|
0x30, 0x16, 0x80, 0x14, 0xfc, 0x7e, 0xb4, 0x94, 0x34, 0xa8, 0x05, 0xd7,
|
|
0xac, 0x7c, 0x88, 0x5c, 0xec, 0x46, 0x3f, 0x39, 0xb5, 0x23, 0x4c, 0x32,
|
|
0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
|
|
0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
|
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
|
|
0x00, 0x8e, 0xa2, 0xa9, 0x08, 0xfe, 0xc6, 0x57, 0xd2, 0x3e, 0xd6, 0x30,
|
|
0x14, 0x12, 0x88, 0x5d, 0x65, 0x9f, 0xfd, 0x21, 0xac, 0x2e, 0x93, 0x70,
|
|
0x1f, 0xd3, 0x7c, 0x29, 0x92, 0x60, 0x3b, 0xcc, 0xb3, 0xaf, 0xe5, 0xc5,
|
|
0x18, 0x1d, 0x8c, 0x83, 0x49, 0xf2, 0xa1, 0xcd, 0x71, 0x6f, 0x66, 0xc1,
|
|
0x41, 0x9a, 0xbf, 0x82, 0xe8, 0xaa, 0x53, 0x70, 0x9e, 0xaa, 0xfa, 0x0e,
|
|
0x08, 0x8f, 0x53, 0x6f, 0x63, 0x39, 0x12, 0x0c, 0x1a, 0x0f, 0x44, 0x33,
|
|
0xa0, 0x06, 0xf9, 0xb6, 0x15, 0xb4, 0x79, 0x66, 0x75, 0x7d, 0x83, 0x4b,
|
|
0xe9, 0xf4, 0xf6, 0xff, 0xac, 0xe2, 0x23, 0x84, 0xdc, 0x8e, 0x50, 0xd9,
|
|
0x8d, 0x50, 0xfb, 0xbf, 0x80, 0xdd, 0x9d, 0xb9, 0xd8, 0x34, 0x11, 0x29,
|
|
0x27, 0xfe, 0x00, 0xf3, 0xfa, 0xf6, 0xc9, 0x69, 0xdb, 0xa2, 0xee, 0xd3,
|
|
0xdb, 0x23, 0x19, 0x25, 0x9b, 0x00, 0xa5, 0x4f, 0x36, 0x4f, 0xae, 0x10,
|
|
0x4f, 0x5a, 0x4c, 0xe2, 0x43, 0x25, 0xad, 0x57, 0x83, 0x39, 0xcf, 0xb1,
|
|
0x89, 0x89, 0x8b, 0x4e, 0xde, 0xab, 0xd8, 0x90, 0x16, 0x77, 0xd1, 0x2f,
|
|
0xcc, 0x0c, 0xf6, 0x0c, 0xbe, 0xd4, 0x98, 0x44, 0x65, 0x5e, 0x0e, 0x66,
|
|
0x12, 0x62, 0x27, 0xd6, 0x9e, 0x4b, 0x72, 0x7a, 0xf6, 0xdf, 0xd7, 0xe5,
|
|
0xa0, 0x41, 0xaa, 0x21, 0x8f, 0xa8, 0x4e, 0xa0, 0xf0, 0x6a, 0x6c, 0xa2,
|
|
0x37, 0xf3, 0xec, 0x0d, 0xe6, 0xf3, 0xd9, 0xeb, 0xa1, 0x6f, 0x56, 0x6c,
|
|
0x08, 0x46, 0x5b, 0x49, 0x2f, 0x2f, 0x8b, 0x0e, 0xda, 0xb1, 0xd1, 0x9c,
|
|
0xc0, 0x14, 0xb2, 0xfb, 0x80, 0x45, 0x06, 0x33, 0x13, 0x18, 0x99, 0x22,
|
|
0xeb, 0x7a, 0x0d, 0x07, 0x87, 0x52, 0x72, 0x7f, 0x92, 0x31, 0x57, 0x0a,
|
|
0x73, 0x94, 0x48, 0xe9, 0x92, 0x21, 0xc1, 0x5a, 0x36, 0xdf, 0xef, 0xa5,
|
|
0x50, 0x33, 0xa4, 0x99, 0x86,
|
|
};
|
|
|
|
|
|
static const byte qc_statements_cert[] = {
|
|
0x30, 0x82, 0x03, 0x13, 0x30, 0x82, 0x01, 0xfb, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x35, 0xa4, 0x48, 0x33, 0x48, 0xea, 0x7c, 0x36, 0xbc,
|
|
0x16, 0x85, 0x72, 0x09, 0x08, 0xbf, 0x3f, 0xa9, 0x08, 0x70, 0x8d, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x12, 0x71, 0x63, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
|
|
0x65, 0x6e, 0x74, 0x73, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17,
|
|
0x0d, 0x32, 0x36, 0x30, 0x39, 0x30, 0x37, 0x31, 0x36, 0x33, 0x39, 0x32,
|
|
0x33, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x39, 0x30, 0x34, 0x31, 0x36,
|
|
0x33, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06,
|
|
0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x71, 0x63, 0x2d, 0x73, 0x74, 0x61,
|
|
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2d, 0x74, 0x65, 0x73, 0x74,
|
|
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
|
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
|
|
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0x83, 0x7a,
|
|
0x84, 0x1a, 0xc5, 0xf8, 0x6d, 0x84, 0x05, 0xff, 0x6d, 0xb7, 0x40, 0xae,
|
|
0x9c, 0x72, 0x27, 0xab, 0x32, 0x70, 0xfa, 0xa6, 0x6e, 0xe6, 0xe7, 0x19,
|
|
0xdc, 0xf6, 0xf2, 0xaa, 0xd7, 0x40, 0x21, 0xbe, 0x04, 0x36, 0xea, 0xf0,
|
|
0x28, 0x87, 0xab, 0x87, 0x97, 0xc2, 0xc3, 0x5f, 0xf3, 0x2e, 0x0d, 0xc1,
|
|
0x2a, 0x95, 0x49, 0xfe, 0x64, 0xd3, 0xb3, 0x6b, 0xd8, 0x31, 0xa1, 0xf4,
|
|
0x26, 0xf5, 0x3c, 0x42, 0x3b, 0x69, 0x36, 0xda, 0x41, 0x80, 0xfc, 0x04,
|
|
0xe7, 0xf7, 0x9c, 0x77, 0x75, 0x41, 0x01, 0xb3, 0xd6, 0x2e, 0x80, 0x60,
|
|
0x90, 0x30, 0xbd, 0x4a, 0xa7, 0x0e, 0xa8, 0x8b, 0xa8, 0x29, 0x0b, 0x33,
|
|
0x56, 0x02, 0x5f, 0x5c, 0x17, 0xeb, 0xa4, 0x0f, 0xe3, 0x8e, 0x6c, 0x93,
|
|
0x85, 0xff, 0x3b, 0xd2, 0x29, 0x83, 0x32, 0x49, 0xf3, 0xfa, 0x1d, 0xa0,
|
|
0x45, 0x45, 0x68, 0x25, 0xa9, 0xa6, 0x99, 0x63, 0xed, 0xa9, 0xdc, 0xe8,
|
|
0xc4, 0xf4, 0x3d, 0x42, 0xb9, 0x65, 0xd1, 0x4e, 0x8e, 0x50, 0x3a, 0xc1,
|
|
0xf1, 0xae, 0xbe, 0xdf, 0x94, 0x65, 0x68, 0x7e, 0x3a, 0x45, 0xca, 0xb4,
|
|
0x81, 0x16, 0x24, 0x23, 0xbd, 0xf1, 0xe1, 0x7a, 0x1b, 0xe1, 0x58, 0xb3,
|
|
0x14, 0xc9, 0x27, 0x1d, 0x9e, 0xe5, 0xd5, 0x2c, 0x04, 0xf6, 0x7a, 0xba,
|
|
0x82, 0xb2, 0x8e, 0x2b, 0xd7, 0x86, 0x2e, 0x4b, 0x99, 0x35, 0xb5, 0x33,
|
|
0xe5, 0x03, 0x04, 0x94, 0x16, 0xe9, 0xf0, 0xfc, 0xb1, 0x84, 0xa3, 0xf7,
|
|
0x72, 0x10, 0x05, 0x72, 0xb6, 0xcd, 0xab, 0x07, 0x1a, 0xf1, 0xe5, 0x52,
|
|
0xc0, 0x74, 0xfa, 0x7d, 0x3e, 0xf8, 0x3d, 0xa6, 0xc6, 0xd1, 0xe1, 0xf3,
|
|
0x09, 0xc3, 0x47, 0x60, 0x10, 0x7c, 0xb7, 0x6e, 0x04, 0x61, 0xea, 0x92,
|
|
0xff, 0xf4, 0x06, 0x60, 0xe3, 0x98, 0xe0, 0xf1, 0x0a, 0xb4, 0xb6, 0x57,
|
|
0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x4b, 0x30, 0x49, 0x30, 0x0f,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
|
|
0x01, 0x01, 0xff, 0x30, 0x17, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
|
|
0x07, 0x01, 0x03, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x02, 0x01,
|
|
0x00, 0x0c, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
|
|
0x16, 0x04, 0x14, 0x94, 0x4c, 0xfb, 0x92, 0x28, 0x3c, 0x1a, 0x0b, 0x0f,
|
|
0x3d, 0x7c, 0x95, 0x3b, 0x55, 0xce, 0x40, 0x39, 0x26, 0x48, 0xf2, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3b, 0x7c, 0xc3, 0xf1, 0x85,
|
|
0x06, 0x51, 0x6a, 0x37, 0xaf, 0xc2, 0xc6, 0x9c, 0x28, 0x4e, 0xff, 0x01,
|
|
0x8e, 0x8a, 0xf4, 0xdd, 0xf4, 0x02, 0x1a, 0xd4, 0x67, 0x57, 0x76, 0xf4,
|
|
0x09, 0x70, 0x1a, 0xca, 0x7a, 0x8b, 0x52, 0x8d, 0x69, 0x7b, 0xcc, 0x54,
|
|
0xec, 0xf5, 0xb8, 0x45, 0xa7, 0xac, 0x12, 0x22, 0xf4, 0x26, 0x69, 0xb8,
|
|
0x52, 0xf5, 0x35, 0x13, 0xce, 0x8e, 0x8d, 0xf3, 0xdd, 0xf8, 0xd1, 0x56,
|
|
0xa1, 0x70, 0x81, 0xd4, 0x7b, 0xdd, 0x33, 0x35, 0xbc, 0x2b, 0xf7, 0x68,
|
|
0x3d, 0x57, 0xf8, 0xea, 0x18, 0x72, 0xe9, 0x48, 0x4a, 0x07, 0x41, 0x3e,
|
|
0x89, 0xd8, 0x13, 0xe8, 0x86, 0x84, 0x25, 0x94, 0x6b, 0x8d, 0x76, 0xfa,
|
|
0x1f, 0xe4, 0x58, 0xef, 0x9c, 0x7d, 0x32, 0xde, 0x19, 0xd8, 0xf1, 0xe0,
|
|
0xe4, 0x2c, 0x1b, 0x61, 0x3b, 0x31, 0xe7, 0x92, 0x1f, 0xc4, 0x80, 0x1c,
|
|
0xcd, 0x54, 0x71, 0xd3, 0x95, 0xfd, 0x14, 0xf4, 0xbc, 0x7b, 0xc1, 0x0b,
|
|
0xd4, 0x54, 0xbc, 0xc9, 0x7a, 0x08, 0xb4, 0x5c, 0x8f, 0xab, 0x62, 0x16,
|
|
0x08, 0x8e, 0x8d, 0xb5, 0xec, 0x06, 0x68, 0xa5, 0x28, 0x3a, 0x97, 0xc3,
|
|
0x9b, 0xe7, 0x27, 0x7a, 0x69, 0x56, 0xb5, 0xd3, 0x3c, 0x36, 0xf4, 0x66,
|
|
0x11, 0xf1, 0xe2, 0xb5, 0xa8, 0xc7, 0xf2, 0x35, 0xdc, 0x8b, 0x37, 0xfb,
|
|
0xbe, 0x01, 0xd4, 0xf3, 0xb9, 0xbc, 0x77, 0x00, 0x7f, 0x29, 0x6f, 0xe8,
|
|
0xca, 0x2c, 0x30, 0x00, 0xa8, 0x81, 0xe1, 0x98, 0xf0, 0x8d, 0xe3, 0x2e,
|
|
0x74, 0x78, 0x06, 0x98, 0x6d, 0x62, 0xb5, 0xb6, 0x2c, 0xb4, 0x5f, 0xe9,
|
|
0xf8, 0x94, 0xce, 0x07, 0x73, 0xfa, 0xc8, 0xed, 0xf9, 0xcd, 0x9e, 0x63,
|
|
0xd0, 0x55, 0x0e, 0x68, 0xf0, 0xbf, 0xbd, 0x2a, 0x22, 0xd8, 0xf6, 0x14,
|
|
0x26, 0xbc, 0x54, 0x5d, 0x3f, 0x85, 0xae, 0xb8, 0xb4, 0x88, 0xfe,
|
|
};
|
|
|
|
#if !defined(IGNORE_NAME_CONSTRAINTS) && \
|
|
(!defined(WOLFSSL_X509_TINY) || \
|
|
defined(WOLFSSL_X509_TINY_NAME_CONSTRAINTS))
|
|
/* CA certificate whose DER orders Name Constraints before Basic
|
|
* Constraints. RFC 5280 4.2.1.10 allows name constraints in a CA
|
|
* certificate; the encoding order of the two extensions is not
|
|
* significant. */
|
|
static const byte nc_before_bc_ca_cert[] = {
|
|
0x30, 0x82, 0x03, 0x99, 0x30, 0x82, 0x02, 0x81, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x53, 0x66, 0x44, 0xc3, 0x8f, 0x51, 0x14, 0xf2, 0x1d,
|
|
0xff, 0x88, 0x4d, 0x61, 0xa3, 0x3e, 0x4d, 0x1b, 0x87, 0x3c, 0x41, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
|
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
|
|
0x04, 0x0a, 0x0c, 0x0c, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20,
|
|
0x54, 0x65, 0x73, 0x74, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x2c, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73,
|
|
0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x20, 0x42, 0x65, 0x66, 0x6f,
|
|
0x72, 0x65, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, 0x43, 0x6f, 0x6e,
|
|
0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x20, 0x43, 0x41, 0x30,
|
|
0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x39, 0x30, 0x39, 0x31, 0x30, 0x30,
|
|
0x35, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x34, 0x36, 0x30, 0x39, 0x30, 0x34,
|
|
0x31, 0x30, 0x30, 0x35, 0x30, 0x38, 0x5a, 0x30, 0x5b, 0x31, 0x0b, 0x30,
|
|
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15,
|
|
0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x77, 0x6f, 0x6c,
|
|
0x66, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x35, 0x30,
|
|
0x33, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2c, 0x4e, 0x61, 0x6d, 0x65,
|
|
0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73,
|
|
0x20, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x42, 0x61, 0x73, 0x69,
|
|
0x63, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74,
|
|
0x73, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
|
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
|
|
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
|
|
0x00, 0xdc, 0x98, 0xdd, 0x37, 0x11, 0xe0, 0x8b, 0xac, 0x3b, 0xdc, 0x7c,
|
|
0xb4, 0xd5, 0x6d, 0x12, 0x9d, 0xbd, 0x36, 0x5b, 0x7d, 0x11, 0xaf, 0x08,
|
|
0x54, 0x0e, 0x89, 0x26, 0x21, 0xbb, 0xc0, 0xaf, 0xd4, 0x83, 0xa2, 0x6a,
|
|
0x4f, 0x43, 0xf6, 0x00, 0x51, 0x87, 0xfa, 0x32, 0x82, 0xb5, 0xe9, 0x1b,
|
|
0x9b, 0x43, 0x19, 0x85, 0x91, 0xbc, 0xfc, 0xa3, 0x56, 0x77, 0x3f, 0x53,
|
|
0x0f, 0x5a, 0x7f, 0x77, 0x6f, 0xb4, 0xc9, 0x4d, 0x30, 0xcf, 0x53, 0x63,
|
|
0x09, 0x1b, 0x53, 0x46, 0x88, 0xa4, 0x34, 0x71, 0x31, 0x50, 0xa0, 0x6e,
|
|
0xd3, 0x57, 0x85, 0xf6, 0xd3, 0x7b, 0xe6, 0xe7, 0xea, 0xbd, 0x60, 0x13,
|
|
0xcb, 0xfb, 0x1e, 0xe6, 0x87, 0x3f, 0x12, 0x5f, 0x8c, 0x0f, 0x49, 0x55,
|
|
0x9d, 0x6f, 0xa7, 0xe6, 0x53, 0xa0, 0xc6, 0x53, 0x33, 0x6a, 0x38, 0x1a,
|
|
0x8a, 0x81, 0x60, 0x1f, 0x0c, 0xde, 0x16, 0xbf, 0x2b, 0x6d, 0xe6, 0xce,
|
|
0x73, 0x85, 0xf9, 0x2c, 0x83, 0xa6, 0x25, 0xc1, 0xa5, 0x98, 0x86, 0x05,
|
|
0x34, 0xfa, 0xe7, 0xb5, 0x0a, 0x57, 0x5d, 0x9f, 0x8f, 0xb8, 0x05, 0x62,
|
|
0x4f, 0xd2, 0x93, 0x13, 0x2c, 0x0c, 0x46, 0xa4, 0x1d, 0x68, 0x6d, 0xbf,
|
|
0xea, 0xa5, 0x70, 0xe7, 0xd7, 0x58, 0xc8, 0xc6, 0x25, 0xb9, 0xc4, 0x08,
|
|
0x37, 0xfc, 0xb4, 0x9c, 0xc6, 0x2e, 0x31, 0x37, 0x90, 0xde, 0xdf, 0xfa,
|
|
0x37, 0x94, 0xbc, 0x5b, 0x48, 0x4e, 0x89, 0x45, 0xd7, 0xd7, 0x72, 0x39,
|
|
0x11, 0x14, 0xa0, 0x7e, 0xd2, 0xdf, 0xa2, 0xdf, 0xd8, 0xc1, 0x20, 0x30,
|
|
0xd0, 0x80, 0x48, 0x6f, 0x98, 0x48, 0xc0, 0x92, 0x3d, 0xd3, 0xb8, 0x66,
|
|
0xfc, 0x09, 0xcc, 0x0e, 0x26, 0x1d, 0xed, 0xd4, 0x2a, 0xb3, 0x4e, 0x50,
|
|
0x05, 0xe7, 0x2a, 0x4c, 0xfe, 0x0f, 0xfb, 0x7a, 0x50, 0xae, 0xf3, 0xed,
|
|
0x9d, 0x61, 0xd1, 0xb4, 0xcf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x55,
|
|
0x30, 0x53, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x1d, 0x1e, 0x01, 0x01, 0xff,
|
|
0x04, 0x14, 0x30, 0x12, 0xa0, 0x10, 0x30, 0x0e, 0x82, 0x0c, 0x2e, 0x65,
|
|
0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
|
|
0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0e, 0x04, 0x16, 0x04, 0x14, 0x26, 0xba, 0xc0, 0x83, 0xcb, 0x42, 0x42,
|
|
0x50, 0xf0, 0xc6, 0x0c, 0x10, 0xfa, 0x6e, 0x6c, 0x1e, 0x7e, 0xa2, 0xe5,
|
|
0x9c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
|
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xb6, 0x88, 0xfe,
|
|
0x2e, 0x22, 0xfb, 0xb1, 0xd6, 0xbe, 0x81, 0xa4, 0x81, 0xba, 0xb6, 0xac,
|
|
0x5d, 0x3d, 0x61, 0x4f, 0x1b, 0xc0, 0x9f, 0x02, 0xa0, 0x04, 0x49, 0x89,
|
|
0x6e, 0x1a, 0x45, 0x5d, 0x33, 0x7f, 0x5b, 0x2f, 0x74, 0x7c, 0xb1, 0x23,
|
|
0xec, 0x21, 0x3a, 0xef, 0xea, 0xd1, 0x91, 0xaf, 0xae, 0x17, 0x0b, 0xde,
|
|
0xe9, 0x1e, 0x4e, 0xb7, 0x6a, 0x52, 0xb7, 0xdb, 0xb5, 0x9d, 0x4b, 0x16,
|
|
0x2c, 0xd8, 0x7a, 0x8e, 0x81, 0xb4, 0xa9, 0x3a, 0x82, 0x19, 0x25, 0xc2,
|
|
0x0f, 0x30, 0xaf, 0x1c, 0xcc, 0xe3, 0x51, 0xd5, 0xa3, 0xb7, 0xc7, 0x88,
|
|
0xd9, 0x46, 0x64, 0x9c, 0x93, 0x02, 0x8e, 0x46, 0x6e, 0x6b, 0x35, 0x70,
|
|
0x3d, 0x4d, 0xec, 0x7c, 0x07, 0x95, 0x1f, 0xc2, 0x76, 0x0e, 0x1d, 0xcd,
|
|
0xa3, 0x39, 0xe6, 0x16, 0x0c, 0x1b, 0xda, 0x36, 0xd1, 0xcb, 0xf5, 0x0b,
|
|
0xb8, 0xbb, 0x68, 0x49, 0x54, 0xaf, 0x60, 0xec, 0xdb, 0xaf, 0x0e, 0x58,
|
|
0xcd, 0x4e, 0xf2, 0xe6, 0x8b, 0x52, 0x7d, 0xd4, 0xa5, 0x8e, 0x90, 0x43,
|
|
0x46, 0xe4, 0x44, 0x62, 0xed, 0xad, 0x95, 0x79, 0x19, 0x04, 0x33, 0x47,
|
|
0x3f, 0xf7, 0xad, 0x90, 0xb4, 0xb2, 0xc2, 0x3e, 0xdd, 0x46, 0x0f, 0x60,
|
|
0xcc, 0x84, 0x51, 0xcb, 0x46, 0x85, 0xf8, 0x12, 0x0e, 0xac, 0xfd, 0x50,
|
|
0xb3, 0x30, 0x0b, 0x96, 0x45, 0x69, 0xad, 0x8e, 0x7c, 0x9d, 0xb0, 0x3a,
|
|
0x64, 0xef, 0x50, 0x41, 0x99, 0xd0, 0x97, 0x2f, 0x56, 0x60, 0xa1, 0x41,
|
|
0x7f, 0xd8, 0x0a, 0x16, 0x0e, 0xb2, 0xbf, 0x8c, 0xe7, 0xb8, 0x8a, 0xbc,
|
|
0xa3, 0xc3, 0x1d, 0x73, 0x5b, 0xda, 0x8b, 0x02, 0x81, 0x47, 0xbc, 0x7a,
|
|
0xa2, 0xf3, 0x2d, 0x9d, 0x0a, 0x24, 0x7f, 0x1f, 0xa6, 0x44, 0xe3, 0x93,
|
|
0xb5, 0x21, 0x63, 0x71, 0xcf, 0xd5, 0xe2, 0x95, 0x6b, 0xbc, 0xfb, 0x36,
|
|
0x54,
|
|
};
|
|
|
|
#ifndef WOLFSSL_NO_ASN_STRICT
|
|
/* Same shape but CA:FALSE: name constraints in a non-CA certificate,
|
|
* which RFC 5280 4.2.1.10 forbids. */
|
|
static const byte nc_before_bc_non_ca_cert[] = {
|
|
0x30, 0x82, 0x03, 0x69, 0x30, 0x82, 0x02, 0x51, 0xa0, 0x03, 0x02, 0x01,
|
|
0x02, 0x02, 0x14, 0x34, 0x7e, 0x45, 0xe9, 0x01, 0x42, 0x86, 0xda, 0x87,
|
|
0x76, 0x00, 0xd8, 0xe7, 0x9d, 0xf2, 0x20, 0x74, 0x8a, 0xa8, 0x41, 0x30,
|
|
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
|
0x05, 0x00, 0x30, 0x46, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
|
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
|
|
0x04, 0x0a, 0x0c, 0x0c, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20,
|
|
0x54, 0x65, 0x73, 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x0c, 0x17, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73,
|
|
0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x20, 0x4e, 0x6f, 0x6e, 0x20,
|
|
0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x39, 0x30, 0x39,
|
|
0x31, 0x30, 0x30, 0x35, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x34, 0x36, 0x30,
|
|
0x39, 0x30, 0x34, 0x31, 0x30, 0x30, 0x35, 0x30, 0x38, 0x5a, 0x30, 0x46,
|
|
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
|
|
0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c,
|
|
0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x54, 0x65, 0x73, 0x74,
|
|
0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x4e,
|
|
0x61, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69,
|
|
0x6e, 0x74, 0x73, 0x20, 0x4e, 0x6f, 0x6e, 0x20, 0x43, 0x41, 0x30, 0x82,
|
|
0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
|
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
|
|
0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdc, 0x98, 0xdd, 0x37, 0x11,
|
|
0xe0, 0x8b, 0xac, 0x3b, 0xdc, 0x7c, 0xb4, 0xd5, 0x6d, 0x12, 0x9d, 0xbd,
|
|
0x36, 0x5b, 0x7d, 0x11, 0xaf, 0x08, 0x54, 0x0e, 0x89, 0x26, 0x21, 0xbb,
|
|
0xc0, 0xaf, 0xd4, 0x83, 0xa2, 0x6a, 0x4f, 0x43, 0xf6, 0x00, 0x51, 0x87,
|
|
0xfa, 0x32, 0x82, 0xb5, 0xe9, 0x1b, 0x9b, 0x43, 0x19, 0x85, 0x91, 0xbc,
|
|
0xfc, 0xa3, 0x56, 0x77, 0x3f, 0x53, 0x0f, 0x5a, 0x7f, 0x77, 0x6f, 0xb4,
|
|
0xc9, 0x4d, 0x30, 0xcf, 0x53, 0x63, 0x09, 0x1b, 0x53, 0x46, 0x88, 0xa4,
|
|
0x34, 0x71, 0x31, 0x50, 0xa0, 0x6e, 0xd3, 0x57, 0x85, 0xf6, 0xd3, 0x7b,
|
|
0xe6, 0xe7, 0xea, 0xbd, 0x60, 0x13, 0xcb, 0xfb, 0x1e, 0xe6, 0x87, 0x3f,
|
|
0x12, 0x5f, 0x8c, 0x0f, 0x49, 0x55, 0x9d, 0x6f, 0xa7, 0xe6, 0x53, 0xa0,
|
|
0xc6, 0x53, 0x33, 0x6a, 0x38, 0x1a, 0x8a, 0x81, 0x60, 0x1f, 0x0c, 0xde,
|
|
0x16, 0xbf, 0x2b, 0x6d, 0xe6, 0xce, 0x73, 0x85, 0xf9, 0x2c, 0x83, 0xa6,
|
|
0x25, 0xc1, 0xa5, 0x98, 0x86, 0x05, 0x34, 0xfa, 0xe7, 0xb5, 0x0a, 0x57,
|
|
0x5d, 0x9f, 0x8f, 0xb8, 0x05, 0x62, 0x4f, 0xd2, 0x93, 0x13, 0x2c, 0x0c,
|
|
0x46, 0xa4, 0x1d, 0x68, 0x6d, 0xbf, 0xea, 0xa5, 0x70, 0xe7, 0xd7, 0x58,
|
|
0xc8, 0xc6, 0x25, 0xb9, 0xc4, 0x08, 0x37, 0xfc, 0xb4, 0x9c, 0xc6, 0x2e,
|
|
0x31, 0x37, 0x90, 0xde, 0xdf, 0xfa, 0x37, 0x94, 0xbc, 0x5b, 0x48, 0x4e,
|
|
0x89, 0x45, 0xd7, 0xd7, 0x72, 0x39, 0x11, 0x14, 0xa0, 0x7e, 0xd2, 0xdf,
|
|
0xa2, 0xdf, 0xd8, 0xc1, 0x20, 0x30, 0xd0, 0x80, 0x48, 0x6f, 0x98, 0x48,
|
|
0xc0, 0x92, 0x3d, 0xd3, 0xb8, 0x66, 0xfc, 0x09, 0xcc, 0x0e, 0x26, 0x1d,
|
|
0xed, 0xd4, 0x2a, 0xb3, 0x4e, 0x50, 0x05, 0xe7, 0x2a, 0x4c, 0xfe, 0x0f,
|
|
0xfb, 0x7a, 0x50, 0xae, 0xf3, 0xed, 0x9d, 0x61, 0xd1, 0xb4, 0xcf, 0x02,
|
|
0x03, 0x01, 0x00, 0x01, 0xa3, 0x4f, 0x30, 0x4d, 0x30, 0x1e, 0x06, 0x03,
|
|
0x55, 0x1d, 0x1e, 0x01, 0x01, 0xff, 0x04, 0x14, 0x30, 0x12, 0xa0, 0x10,
|
|
0x30, 0x0e, 0x82, 0x0c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
|
0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
|
|
0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0e, 0x04, 0x16, 0x04, 0x14, 0x26, 0xba, 0xc0, 0x83, 0xcb, 0x42, 0x42,
|
|
0x50, 0xf0, 0xc6, 0x0c, 0x10, 0xfa, 0x6e, 0x6c, 0x1e, 0x7e, 0xa2, 0xe5,
|
|
0x9c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
|
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa6, 0xc0, 0xf7,
|
|
0xed, 0x0a, 0x7c, 0x56, 0xa9, 0xc4, 0xdc, 0xc1, 0xb2, 0x33, 0xff, 0x1e,
|
|
0x88, 0x3c, 0xc3, 0x86, 0x79, 0x5a, 0x6a, 0xba, 0x73, 0xb1, 0xc8, 0x53,
|
|
0x18, 0x01, 0x54, 0xcc, 0x83, 0xb3, 0xe1, 0xde, 0x2c, 0x69, 0xa4, 0x45,
|
|
0x35, 0x0a, 0xdd, 0xc3, 0xe6, 0x8e, 0xe0, 0xf8, 0xba, 0xd6, 0xbc, 0xbd,
|
|
0xf6, 0xad, 0x02, 0x35, 0xd3, 0xd9, 0xe4, 0xb0, 0x7c, 0x65, 0x13, 0x1c,
|
|
0xad, 0x29, 0x7d, 0xbd, 0x49, 0x0c, 0x81, 0xa3, 0xf5, 0xcb, 0xc2, 0x3c,
|
|
0x43, 0x42, 0x9c, 0x3d, 0xd6, 0x15, 0xa4, 0x8d, 0x8d, 0x19, 0x15, 0xae,
|
|
0x84, 0x0f, 0xbc, 0x58, 0x85, 0xb7, 0x03, 0xd1, 0xb3, 0x81, 0xfc, 0xed,
|
|
0xed, 0x10, 0x71, 0x07, 0xe5, 0x98, 0xb6, 0xca, 0x71, 0x6d, 0xfe, 0xb7,
|
|
0xbe, 0x78, 0x8d, 0x16, 0xe9, 0x64, 0xc1, 0x20, 0xb9, 0x6a, 0xf7, 0xdc,
|
|
0x88, 0x75, 0xdf, 0x0f, 0x90, 0xf7, 0x61, 0xcd, 0x15, 0x58, 0xe5, 0x38,
|
|
0xae, 0x2d, 0x4e, 0x18, 0x29, 0xc9, 0xbc, 0x6a, 0xd6, 0x44, 0xed, 0x58,
|
|
0x59, 0x3b, 0x78, 0xaf, 0x23, 0xa0, 0x82, 0x10, 0xcc, 0x43, 0xdc, 0x1c,
|
|
0xe0, 0x38, 0xf6, 0x73, 0xcd, 0xe9, 0xc1, 0x72, 0xb6, 0xd4, 0xb8, 0x49,
|
|
0x4b, 0x8e, 0x39, 0x26, 0x8d, 0xac, 0x13, 0x69, 0x02, 0x04, 0xbf, 0xfd,
|
|
0x97, 0x2b, 0xc4, 0x55, 0xa6, 0xf7, 0x84, 0x4a, 0x72, 0xb4, 0x3c, 0x11,
|
|
0x74, 0x86, 0xc1, 0xd3, 0xb9, 0xd1, 0x97, 0x63, 0x92, 0x63, 0x5f, 0x5b,
|
|
0xf8, 0x68, 0xc1, 0x8c, 0x71, 0xa8, 0xf9, 0xef, 0x85, 0xc9, 0x59, 0x44,
|
|
0x50, 0x09, 0xa4, 0xe6, 0x6c, 0x31, 0xfd, 0xe2, 0x46, 0x74, 0x80, 0x85,
|
|
0x72, 0x53, 0x5a, 0x1d, 0x0d, 0xad, 0x17, 0x24, 0xaa, 0xb0, 0x50, 0xd6,
|
|
0x1b, 0xe6, 0xd4, 0x03, 0x9e, 0x01, 0x67, 0x83, 0x74, 0x80, 0x7c, 0xd6,
|
|
0x84,
|
|
};
|
|
#endif /* !WOLFSSL_NO_ASN_STRICT */
|
|
#endif /* !IGNORE_NAME_CONSTRAINTS && name constraints supported */
|
|
|
|
#endif /* !NO_ASN && !NO_CERTS && !NO_RSA */
|
|
|
|
|
|
/*
|
|
* A tbs signatureAlgorithm that differs from the outer signatureAlgorithm.
|
|
* RFC 5280 4.1.1.2 and 4.1.2.3 require the two to match. Only the tbs copy
|
|
* is covered by the signature, so a mismatch must be rejected rather than
|
|
* resolved in favour of either field. The variant below claims
|
|
* sha384WithRSAEncryption inside the tbs while the certificate is really
|
|
* signed with the outer sha256WithRSAEncryption.
|
|
*/
|
|
int test_ParseCert_tbs_sig_oid_mismatch(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA)
|
|
DecodedCert cert;
|
|
WOLFSSL_CERT_MANAGER* cm;
|
|
|
|
/* Control: the original certificate parses and keeps the signature
|
|
* algorithm. */
|
|
wc_InitDecodedCert(&cert, sig_oid_base, (word32)sizeof(sig_oid_base),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectIntEQ(cert.signatureOID, CTC_SHA256wRSA);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* Mismatch variant: tbs says sha384, outer (and the real signature)
|
|
* say sha256. RFC 5280 4.1.1.2 and 4.1.2.3 require the two to match.
|
|
* Only the tbs copy is covered by the signature, so a mismatch must be
|
|
* rejected rather than resolved in favour of either field. */
|
|
wc_InitDecodedCert(&cert, sig_oid_mismatch,
|
|
(word32)sizeof(sig_oid_mismatch), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_SIG_OID_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* The mismatch is rejected on load too, so it can never reach
|
|
* signature verification. */
|
|
cm = wolfSSL_CertManagerNew();
|
|
ExpectNotNull(cm);
|
|
if (cm != NULL) {
|
|
ExpectIntNE(wolfSSL_CertManagerLoadCABuffer_ex(cm, sig_oid_mismatch,
|
|
(long)sizeof(sig_oid_mismatch), WOLFSSL_FILETYPE_ASN1, 0,
|
|
WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY), WOLFSSL_SUCCESS);
|
|
wolfSSL_CertManagerFree(cm);
|
|
}
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* A certificate with an empty subjectAltName (SEQUENCE OF with no members).
|
|
* RFC 5280 4.2.1.6 requires at least one entry and GeneralNames is
|
|
* SEQUENCE SIZE (1..MAX), so parsing must fail.
|
|
*/
|
|
int test_ParseCert_empty_san(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA)
|
|
DecodedCert cert;
|
|
|
|
/* RFC 5280 4.2.1.6: if the subjectAltName extension is present the
|
|
* sequence MUST contain at least one entry, and GeneralNames is
|
|
* SEQUENCE SIZE (1..MAX). An empty one is rejected. */
|
|
wc_InitDecodedCert(&cert, empty_san_cert, (word32)sizeof(empty_san_cert),
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
/* Rejected on load, so it never reaches name checking. */
|
|
ExpectNull(wolfSSL_X509_d2i(NULL, empty_san_cert,
|
|
(int)sizeof(empty_san_cert)));
|
|
#endif
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* A certificate whose subject packs several AttributeTypeAndValues into one
|
|
* SET (multi-valued RDN). RFC 5280 4.1.2.4 defines a
|
|
* RelativeDistinguishedName as SET SIZE (1..MAX) OF AttributeTypeAndValue,
|
|
* so parsing must succeed with every attribute stored, while an
|
|
* AttributeTypeAndValue outside the SET must be rejected.
|
|
*/
|
|
int test_ParseCert_multi_valued_rdn(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA)
|
|
DecodedCert cert;
|
|
|
|
/* RFC 5280 4.1.2.4: RelativeDistinguishedName is
|
|
* SET SIZE (1..MAX) OF AttributeTypeAndValue, so one SET may hold
|
|
* several attributes. */
|
|
wc_InitDecodedCert(&cert, mv_rdn_cert, (word32)sizeof(mv_rdn_cert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
/* All three attributes of the packed RDN were stored. */
|
|
ExpectNotNull(XSTRSTR(cert.subject, "InfoNotary Test"));
|
|
ExpectNotNull(XSTRSTR(cert.subject, "Multi Value RDN CA"));
|
|
ExpectNotNull(XSTRSTR(cert.subject, "BG"));
|
|
ExpectNotNull(XSTRSTR(cert.issuer, "InfoNotary Test"));
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* Negative: same certificate with the subject RDN's SET length reduced
|
|
* so its third AttributeTypeAndValue sits after the SET ends, where
|
|
* RDNSequence requires a SET. Parsing must stop at the SET boundary and
|
|
* reject it, not absorb the stray attribute into the RDN.
|
|
*
|
|
* Template parser only. The original parser retries an
|
|
* AttributeTypeAndValue that lacks a SET header as a bare SEQUENCE, so
|
|
* it accepts this encoding. */
|
|
#ifdef WOLFSSL_ASN_TEMPLATE
|
|
{
|
|
byte bad[sizeof(mv_rdn_cert)];
|
|
|
|
XMEMCPY(bad, mv_rdn_cert, sizeof(mv_rdn_cert));
|
|
/* Subject RDN SET content length: 3 attributes -> 2. */
|
|
ExpectIntEQ(bad[MV_RDN_SET_LEN_IDX], 0x3e);
|
|
bad[MV_RDN_SET_LEN_IDX] = 0x23;
|
|
wc_InitDecodedCert(&cert, bad, (word32)sizeof(bad), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* Negative: first AttributeTypeAndValue SEQUENCE extended to hold
|
|
* the second one. The nested AttributeTypeAndValue is trailing data
|
|
* of the first, not a member of the SET. */
|
|
XMEMCPY(bad, mv_rdn_cert, sizeof(mv_rdn_cert));
|
|
ExpectIntEQ(bad[MV_RDN_AVA_LEN_IDX], 0x09);
|
|
ExpectIntEQ(bad[MV_RDN_AVA_LEN_IDX + 11], 0x16);
|
|
bad[MV_RDN_AVA_LEN_IDX] = 0x09 + 2 + 0x16;
|
|
wc_InitDecodedCert(&cert, bad, (word32)sizeof(bad), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_PARSE_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* Name constraints are valid in a CA certificate regardless of where the
|
|
* Basic Constraints extension sits in the DER. RFC 5280 4.2.1.10 restricts
|
|
* the extension to CA certificates, so the decision needs isCA, which comes
|
|
* from Basic Constraints and may be encoded later.
|
|
*/
|
|
int test_ParseCert_nc_before_basic_constraints(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA) && \
|
|
!defined(IGNORE_NAME_CONSTRAINTS) && \
|
|
(!defined(WOLFSSL_X509_TINY) || defined(WOLFSSL_X509_TINY_NAME_CONSTRAINTS))
|
|
DecodedCert cert;
|
|
|
|
/* CA certificate: name constraints precede basic constraints. */
|
|
wc_InitDecodedCert(&cert, nc_before_bc_ca_cert,
|
|
(word32)sizeof(nc_before_bc_ca_cert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectIntEQ(cert.isCA, 1);
|
|
ExpectIntEQ(cert.extNameConstraintSet, 1);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* It also loads as a CA. The load needs a TLS method for its
|
|
* temporary context. */
|
|
#if !defined(NO_TLS) && \
|
|
(!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
|
|
{
|
|
WOLFSSL_CERT_MANAGER* cm = wolfSSL_CertManagerNew();
|
|
ExpectNotNull(cm);
|
|
if (cm != NULL) {
|
|
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer_ex(cm,
|
|
nc_before_bc_ca_cert, (long)sizeof(nc_before_bc_ca_cert),
|
|
WOLFSSL_FILETYPE_ASN1, 0, WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY),
|
|
WOLFSSL_SUCCESS);
|
|
wolfSSL_CertManagerFree(cm);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Same ordering but CA:FALSE is still rejected. */
|
|
#ifndef WOLFSSL_NO_ASN_STRICT
|
|
wc_InitDecodedCert(&cert, nc_before_bc_non_ca_cert,
|
|
(word32)sizeof(nc_before_bc_non_ca_cert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* A certificate with a critical qcStatements extension (1.3.6.1.5.5.7.1.3,
|
|
* RFC 3739 3.2.6). The statements are not processed, and RFC 5280 4.2
|
|
* requires rejecting a critical extension whose information cannot be
|
|
* processed, so parsing must fail.
|
|
*/
|
|
int test_ParseCert_critical_qc_statements(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA)
|
|
DecodedCert cert;
|
|
|
|
/* RFC 5280 4.2: a critical extension whose information cannot be
|
|
* processed must be rejected. RFC 3739 3.2.6 makes every statement in a
|
|
* critical qcStatements critical, and the statements are not processed,
|
|
* so the certificate is flagged. */
|
|
wc_InitDecodedCert(&cert, qc_statements_cert,
|
|
(word32)sizeof(qc_statements_cert), NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL),
|
|
WC_NO_ERR_TRACE(ASN_CRIT_EXT_E));
|
|
wc_FreeDecodedCert(&cert);
|
|
#endif
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
|
|
/*
|
|
* MC/DC wave 2 - decision-targeted negative paths for PKCS#8 wrap/parse
|
|
* and RSA key decode. Targets argument-check, short-buffer, and
|
|
* truncated-DER decision branches in wolfcrypt/src/asn.c without touching
|
|
* the library source.
|
|
*/
|
|
int test_wc_AsnDecisionCoverage(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
|
|
#if !defined(NO_ASN) && !defined(NO_RSA) && \
|
|
(defined(USE_CERT_BUFFERS_1024) || defined(USE_CERT_BUFFERS_2048)) && \
|
|
!defined(HAVE_FIPS)
|
|
/* ---- wc_RsaPublicKeyDecode: truncated / bad-arg decision branches ---- */
|
|
{
|
|
RsaKey key;
|
|
const byte* derKey;
|
|
word32 derKeySz;
|
|
word32 idx;
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
ExpectIntEQ(wc_InitRsaKey(&key, HEAP_HINT), 0);
|
|
|
|
#ifdef USE_CERT_BUFFERS_2048
|
|
derKey = client_keypub_der_2048;
|
|
derKeySz = (word32)sizeof_client_keypub_der_2048;
|
|
#else
|
|
derKey = client_keypub_der_1024;
|
|
derKeySz = (word32)sizeof_client_keypub_der_1024;
|
|
#endif
|
|
|
|
/* Null arg branches. */
|
|
idx = 0;
|
|
ExpectIntEQ(wc_RsaPublicKeyDecode(NULL, &idx, &key, derKeySz),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(wc_RsaPublicKeyDecode(derKey, NULL, &key, derKeySz),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(wc_RsaPublicKeyDecode(derKey, &idx, NULL, derKeySz),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
/* Truncated input: header says more data than buffer length. */
|
|
idx = 0;
|
|
ExpectIntLT(wc_RsaPublicKeyDecode(derKey, &idx, &key, 4), 0);
|
|
|
|
/* wc_RsaPublicKeyDecodeRaw null-arg branches. */
|
|
{
|
|
static const byte nBuf[] = { 0xC0 };
|
|
static const byte eBuf[] = { 0x01, 0x00, 0x01 };
|
|
ExpectIntEQ(wc_RsaPublicKeyDecodeRaw(NULL, sizeof(nBuf),
|
|
eBuf, sizeof(eBuf), &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(wc_RsaPublicKeyDecodeRaw(nBuf, sizeof(nBuf),
|
|
NULL, sizeof(eBuf), &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(wc_RsaPublicKeyDecodeRaw(nBuf, sizeof(nBuf),
|
|
eBuf, sizeof(eBuf), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
}
|
|
|
|
DoExpectIntEQ(wc_FreeRsaKey(&key), 0);
|
|
}
|
|
|
|
/* ---- wc_GetPkcs8TraditionalOffset: argument-check branches ---- */
|
|
{
|
|
byte buf[8] = { 0x30, 0x82, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00 };
|
|
word32 idx;
|
|
|
|
idx = 0;
|
|
ExpectIntEQ(wc_GetPkcs8TraditionalOffset(NULL, &idx, sizeof(buf)),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
ExpectIntEQ(wc_GetPkcs8TraditionalOffset(buf, NULL, sizeof(buf)),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
/* idx >= sz decision branch - any negative return exercises the
|
|
* short-input guard (BUFFER_E in current code, but we do not pin
|
|
* the exact code here). */
|
|
idx = sizeof(buf);
|
|
ExpectIntLT(wc_GetPkcs8TraditionalOffset(buf, &idx, sizeof(buf)), 0);
|
|
/* Non-PKCS#8 blob: malformed DER decision branch. */
|
|
{
|
|
byte bogus[4] = { 0x00, 0x00, 0x00, 0x00 };
|
|
idx = 0;
|
|
ExpectIntLT(wc_GetPkcs8TraditionalOffset(bogus, &idx,
|
|
sizeof(bogus)), 0);
|
|
}
|
|
}
|
|
|
|
/* ---- wc_CreatePKCS8Key: size-query and bad-arg branches ----
|
|
* Uses the existing RSA private key DER from certs_test.h to avoid
|
|
* runtime key generation (which requires WOLFSSL_KEY_GEN and a usable
|
|
* RNG and is not available in every retained lane). */
|
|
{
|
|
#ifdef USE_CERT_BUFFERS_2048
|
|
const byte* rsaDer = client_key_der_2048;
|
|
word32 rsaDerSz = (word32)sizeof_client_key_der_2048;
|
|
#else
|
|
const byte* rsaDer = client_key_der_1024;
|
|
word32 rsaDerSz = (word32)sizeof_client_key_der_1024;
|
|
#endif
|
|
byte pkcs8[2048];
|
|
word32 pkcs8Sz;
|
|
|
|
/* Size-query: out == NULL should return LENGTH_ONLY_E and set
|
|
* outSz. */
|
|
pkcs8Sz = 0;
|
|
ExpectIntEQ(wc_CreatePKCS8Key(NULL, &pkcs8Sz, (byte*)rsaDer,
|
|
rsaDerSz, RSAk, NULL, 0),
|
|
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
|
|
ExpectIntGT(pkcs8Sz, 0);
|
|
|
|
/* Null outSz branch. */
|
|
ExpectIntEQ(wc_CreatePKCS8Key(pkcs8, NULL, (byte*)rsaDer, rsaDerSz,
|
|
RSAk, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
}
|
|
#endif /* !NO_ASN && !NO_RSA && cert-buffers && !HAVE_FIPS */
|
|
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/*
|
|
* MC/DC wave 2 - feature-oriented positive paths to lift asn.c MC/DC by
|
|
* exercising real cert parsing, PKCS#8 round trips, ECC key decoding, and
|
|
* PEM<->DER conversions on the static cert buffers (no new fixtures).
|
|
*/
|
|
int test_wc_AsnFeatureCoverage(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_RSA) && \
|
|
defined(USE_CERT_BUFFERS_2048) && !defined(HAVE_FIPS)
|
|
/* ---- DecodedCert: full client cert parse, with subject + pubkey ---- */
|
|
{
|
|
struct DecodedCert cert;
|
|
byte pubKey[512];
|
|
word32 pubKeySz = sizeof(pubKey);
|
|
char subject[256];
|
|
word32 subjectSz = sizeof(subject);
|
|
|
|
wc_InitDecodedCert(&cert, client_cert_der_2048,
|
|
sizeof_client_cert_der_2048, NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
ExpectIntEQ(wc_GetPubKeyDerFromCert(&cert, pubKey, &pubKeySz), 0);
|
|
ExpectIntGT(pubKeySz, 0);
|
|
ExpectIntEQ(wc_GetDecodedCertSubject(&cert, subject, &subjectSz), 0);
|
|
wc_FreeDecodedCert(&cert);
|
|
}
|
|
|
|
/* ---- DecodedCert: server cert parse and SubjectPublicKeyInfo extract -- */
|
|
{
|
|
struct DecodedCert cert;
|
|
byte spki[1024];
|
|
word32 spkiSz = sizeof(spki);
|
|
|
|
wc_InitDecodedCert(&cert, server_cert_der_2048,
|
|
sizeof_server_cert_der_2048, NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&cert);
|
|
|
|
/* Some retained builds return 0 on success and write spkiSz; others
|
|
* return spkiSz directly. Accept any non-negative result and require
|
|
* a non-zero output size. */
|
|
ExpectIntGE(wc_GetSubjectPubKeyInfoDerFromCert(server_cert_der_2048,
|
|
sizeof_server_cert_der_2048, spki, &spkiSz), 0);
|
|
ExpectIntGT(spkiSz, 0);
|
|
}
|
|
|
|
/* ---- PKCS#8: round trip wrap then offset extract ---- */
|
|
{
|
|
byte pkcs8[2048];
|
|
word32 pkcs8Sz = 0;
|
|
word32 idx;
|
|
int wrapSz;
|
|
|
|
/* Size query first. */
|
|
ExpectIntEQ(wc_CreatePKCS8Key(NULL, &pkcs8Sz,
|
|
(byte*)client_key_der_2048, sizeof_client_key_der_2048, RSAk,
|
|
NULL, 0), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
|
|
ExpectIntGT(pkcs8Sz, 0);
|
|
|
|
wrapSz = wc_CreatePKCS8Key(pkcs8, &pkcs8Sz,
|
|
(byte*)client_key_der_2048, sizeof_client_key_der_2048, RSAk,
|
|
NULL, 0);
|
|
ExpectIntGT(wrapSz, 0);
|
|
|
|
if (wrapSz > 0) {
|
|
idx = 0;
|
|
ExpectIntGE(wc_GetPkcs8TraditionalOffset(pkcs8, &idx,
|
|
(word32)wrapSz), 0);
|
|
ExpectIntGT(idx, 0);
|
|
}
|
|
}
|
|
|
|
/* ---- CA cert parse: exercises CA-specific decision branches ---- */
|
|
{
|
|
struct DecodedCert caCert;
|
|
wc_InitDecodedCert(&caCert, ca_cert_der_2048, sizeof_ca_cert_der_2048,
|
|
NULL);
|
|
ExpectIntEQ(wc_ParseCert(&caCert, CA_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&caCert);
|
|
}
|
|
|
|
/* ---- Parse server cert a second time with CERT_TYPE + verify off ----
|
|
* to touch ParseCertRelative decision branches that the first pass skips.
|
|
*/
|
|
{
|
|
struct DecodedCert cert2;
|
|
wc_InitDecodedCert(&cert2, server_cert_der_2048,
|
|
sizeof_server_cert_der_2048, NULL);
|
|
ExpectIntEQ(wc_ParseCert(&cert2, CERT_TYPE, NO_VERIFY, NULL), 0);
|
|
wc_FreeDecodedCert(&cert2);
|
|
}
|
|
|
|
/* ---- PEM<->DER conversion round trip on the client cert ---- */
|
|
#ifdef WOLFSSL_DER_TO_PEM
|
|
{
|
|
byte pem[4096];
|
|
int pemSz;
|
|
|
|
pemSz = wc_DerToPem(client_cert_der_2048, sizeof_client_cert_der_2048,
|
|
pem, sizeof(pem), CERT_TYPE);
|
|
ExpectIntGT(pemSz, 0);
|
|
|
|
#ifdef WOLFSSL_PEM_TO_DER
|
|
if (pemSz > 0) {
|
|
byte der[2048];
|
|
int derSz;
|
|
derSz = wc_CertPemToDer(pem, pemSz, der, sizeof(der), CERT_TYPE);
|
|
ExpectIntGT(derSz, 0);
|
|
if (derSz > 0)
|
|
ExpectBufEQ(der, client_cert_der_2048,
|
|
sizeof_client_cert_der_2048);
|
|
}
|
|
#endif
|
|
}
|
|
#endif /* WOLFSSL_DER_TO_PEM */
|
|
#endif /* !NO_ASN && !NO_RSA && USE_CERT_BUFFERS_2048 && !HAVE_FIPS */
|
|
|
|
#if !defined(NO_ASN) && defined(HAVE_ECC) && \
|
|
defined(USE_CERT_BUFFERS_256) && !defined(HAVE_FIPS)
|
|
/* ---- ECC private + public key DER decode round trip ---- */
|
|
{
|
|
ecc_key ecKey;
|
|
word32 idx = 0;
|
|
byte pubKeyDer[256];
|
|
int derSz;
|
|
|
|
XMEMSET(&ecKey, 0, sizeof(ecKey));
|
|
ExpectIntEQ(wc_ecc_init(&ecKey), 0);
|
|
ExpectIntEQ(wc_EccPrivateKeyDecode(ecc_clikey_der_256, &idx, &ecKey,
|
|
sizeof_ecc_clikey_der_256), 0);
|
|
|
|
derSz = wc_EccPublicKeyToDer(&ecKey, pubKeyDer, sizeof(pubKeyDer), 1);
|
|
ExpectIntGT(derSz, 0);
|
|
|
|
if (derSz > 0) {
|
|
ecc_key pubOnly;
|
|
word32 idx2 = 0;
|
|
XMEMSET(&pubOnly, 0, sizeof(pubOnly));
|
|
ExpectIntEQ(wc_ecc_init(&pubOnly), 0);
|
|
ExpectIntEQ(wc_EccPublicKeyDecode(pubKeyDer, &idx2, &pubOnly,
|
|
(word32)derSz), 0);
|
|
wc_ecc_free(&pubOnly);
|
|
}
|
|
wc_ecc_free(&ecKey);
|
|
}
|
|
#endif /* !NO_ASN && HAVE_ECC && USE_CERT_BUFFERS_256 && !HAVE_FIPS */
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* AltNameNewEx() stores the name inside the entry's own allocation, so
|
|
* FreeAltNames() releases both with one free. Check the copy, the length, the
|
|
* terminator, and that a NULL or empty name still yields a usable entry.
|
|
*/
|
|
int test_wc_AltNameNewEx(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_ASN) && !defined(NO_CERTS) && \
|
|
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
|
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
|
const char name[] = "example.com";
|
|
DNS_entry* entry = NULL;
|
|
|
|
ExpectNotNull(entry = AltNameNewEx(name, (int)XSTRLEN(name), NULL));
|
|
if (entry != NULL) {
|
|
ExpectIntEQ(entry->len, (int)XSTRLEN(name));
|
|
ExpectNotNull(entry->name);
|
|
ExpectIntEQ(XMEMCMP(entry->name, name, XSTRLEN(name)), 0);
|
|
/* The name is NUL terminated and part of the entry's allocation. */
|
|
ExpectIntEQ(entry->name[XSTRLEN(name)], '\0');
|
|
ExpectIntEQ(entry->nameStored, 0);
|
|
/* The name region sits after the struct in the entry's own block,
|
|
* which is the property that makes one allocation and one free
|
|
* correct. */
|
|
ExpectTrue((const char*)entry < entry->name);
|
|
ExpectTrue(entry->name <
|
|
(const char*)entry + sizeof(DNS_entry) + XSTRLEN(name) + 1);
|
|
}
|
|
FreeAltNames(entry, NULL);
|
|
entry = NULL;
|
|
|
|
/* A length with no name to go with it is rejected rather than leaving
|
|
* len covering bytes that were never written, and a negative length is
|
|
* rejected rather than used as a size. */
|
|
ExpectNull(AltNameNewEx(NULL, 1, NULL));
|
|
ExpectNull(AltNameNewEx(name, -1, NULL));
|
|
|
|
/* An empty name is still a valid entry with a terminated string. */
|
|
ExpectNotNull(entry = AltNameNewEx(NULL, 0, NULL));
|
|
if (entry != NULL) {
|
|
ExpectIntEQ(entry->len, 0);
|
|
ExpectNotNull(entry->name);
|
|
ExpectIntEQ(entry->name[0], '\0');
|
|
}
|
|
FreeAltNames(entry, NULL);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* RFC 5280 4.2.1.4 defines PolicyInformation.policyQualifiers as
|
|
* SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL, so a policy set
|
|
* without qualifiers must encode as a SEQUENCE holding only the OID, never
|
|
* an empty "30 00" qualifier SEQUENCE after it. */
|
|
int test_SetCertificatePolicies_no_empty_qualifiers(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \
|
|
!defined(NO_RSA) && !defined(NO_CERTS) && !defined(NO_ASN) && \
|
|
!defined(NO_ASN_TIME) && !defined(NO_SHA256) && \
|
|
!defined(WC_NO_RNG) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \
|
|
!defined(WOLFSSL_RSA_VERIFY_ONLY) && \
|
|
defined(USE_CERT_BUFFERS_2048) && !defined(HAVE_FIPS)
|
|
{
|
|
RsaKey key;
|
|
WC_RNG rng;
|
|
Cert cert;
|
|
byte* der;
|
|
int certSz = 0;
|
|
word32 idx = 0;
|
|
/* "1.2.3" */
|
|
const byte oidTlv[] = { 0x06, 0x02, 0x2a, 0x03 };
|
|
|
|
der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
ExpectNotNull(der);
|
|
|
|
XMEMSET(&key, 0, sizeof(key));
|
|
XMEMSET(&rng, 0, sizeof(rng));
|
|
ExpectIntEQ(wc_InitRsaKey(&key, HEAP_HINT), 0);
|
|
ExpectIntEQ(wc_InitRng(&rng), 0);
|
|
ExpectIntEQ(wc_RsaPrivateKeyDecode(client_key_der_2048, &idx, &key,
|
|
sizeof_client_key_der_2048), 0);
|
|
|
|
ExpectIntEQ(wc_InitCert(&cert), 0);
|
|
cert.isCA = 0;
|
|
cert.sigType = CTC_SHA256wRSA;
|
|
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE - 1);
|
|
XSTRNCPY(cert.subject.commonName, "www.wolfssl.com",
|
|
CTC_NAME_SIZE - 1);
|
|
XSTRNCPY(cert.certPolicies[0], "1.2.3", CTC_MAX_CERTPOL_SZ - 1);
|
|
cert.certPoliciesNb = 1;
|
|
|
|
if (der != NULL) {
|
|
ExpectIntGT(certSz = wc_MakeSelfCert(&cert, der, FOURK_BUF, &key,
|
|
&rng), 0);
|
|
}
|
|
|
|
if (EXPECT_SUCCESS()) {
|
|
int i;
|
|
int found = 0;
|
|
|
|
for (i = 2; i + (int)sizeof(oidTlv) <= certSz; i++) {
|
|
if (XMEMCMP(der + i, oidTlv, sizeof(oidTlv)) == 0 &&
|
|
der[i - 2] == 0x30) {
|
|
/* The enclosing PolicyInformation SEQUENCE must be
|
|
* exactly the OID TLV: 30 04 06 02 2a 03. A length of
|
|
* 6 would mean an empty policyQualifiers follows. */
|
|
ExpectIntEQ(der[i - 1], sizeof(oidTlv));
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
ExpectIntEQ(found, 1);
|
|
}
|
|
|
|
wc_FreeRng(&rng);
|
|
wc_FreeRsaKey(&key);
|
|
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|