diff --git a/certs/1024/client-keyPub.der b/certs/1024/client-keyPub.der new file mode 100644 index 000000000..a5c1817d9 Binary files /dev/null and b/certs/1024/client-keyPub.der differ diff --git a/certs/client-keyPub.der b/certs/client-keyPub.der new file mode 100644 index 000000000..b27f0e9bb Binary files /dev/null and b/certs/client-keyPub.der differ diff --git a/certs/ecc-keyPub.der b/certs/ecc-keyPub.der new file mode 100644 index 000000000..91aa79bee Binary files /dev/null and b/certs/ecc-keyPub.der differ diff --git a/configure.ac b/configure.ac index 57d6eb83d..01cb9f44b 100644 --- a/configure.ac +++ b/configure.ac @@ -226,7 +226,7 @@ AC_ARG_ENABLE([bump], if test "$ENABLED_BUMP" = "yes" then - AM_CFLAGS="$AM_CFLAGS -DLARGE_STATIC_BUFFERS -DWOLFSSL_CERT_GEN -DWOLFSSL_KEY_GEN -DHUGE_SESSION_CACHE -DOPENSSL_EXTRA -DFP_MAX_BITS=8192 -DWOLFSSL_DER_LOAD -DWOLFSSL_ALT_NAMES -DWOLFSSL_TEST_CERT" + AM_CFLAGS="$AM_CFLAGS -DLARGE_STATIC_BUFFERS -DWOLFSSL_CERT_GEN -DWOLFSSL_KEY_GEN -DHUGE_SESSION_CACHE -DOPENSSL_EXTRA -DFP_MAX_BITS=8192 -DWOLFSSL_DER_LOAD -DWOLFSSL_ALT_NAMES -DWOLFSSL_TEST_CERT -DWOLFSSL_CERT_EXT" fi ENABLED_SLOWMATH="yes" @@ -638,6 +638,23 @@ then fi +# CERT REQUEST EXTENSION +AC_ARG_ENABLE([certext], + [ --enable-certext Enable cert request extensions (default: disabled)], + [ ENABLED_CERTEXT=$enableval ], + [ ENABLED_CERTEXT=no ] + ) + +if test "$ENABLED_CERTEXT" = "yes" +then + if test "$ENABLED_CERTEXT" = "no" + then + AC_MSG_ERROR([cannot enable certext without enabling certgen.]) + fi + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_EXT" +fi + + # SEP AC_ARG_ENABLE([sep], [ --enable-sep Enable sep extensions (default: disabled)], @@ -1661,6 +1678,11 @@ then ENABLED_CERTREQ="yes" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_REQ" fi + if test "x$ENABLED_CERTEXT" = "xno" + then + ENABLED_CERTEXT="yes" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_EXT" + fi if test "x$ENABLED_PKCS7" = "xno" then ENABLED_PKCS7="yes" @@ -2348,6 +2370,7 @@ echo " * BLAKE2: $ENABLED_BLAKE2" echo " * keygen: $ENABLED_KEYGEN" echo " * certgen: $ENABLED_CERTGEN" echo " * certreq: $ENABLED_CERTREQ" +echo " * certext: $ENABLED_CERTEXT" echo " * HC-128: $ENABLED_HC128" echo " * RABBIT: $ENABLED_RABBIT" echo " * CHACHA: $ENABLED_CHACHA" diff --git a/gencertbuf.pl b/gencertbuf.pl index d3d116695..d58cd5aa7 100755 --- a/gencertbuf.pl +++ b/gencertbuf.pl @@ -20,6 +20,7 @@ my $outputFile = "./wolfssl/certs_test.h"; my @fileList_1024 = ( [ "./certs/1024/client-key.der", "client_key_der_1024" ], + [ "./certs/1024/client-keyPub.der", "client_keypub_der_1024" ], [ "./certs/1024/client-cert.der", "client_cert_der_1024" ], [ "./certs/1024/dh1024.der", "dh_key_der_1024" ], [ "./certs/1024/dsa1024.der", "dsa_key_der_1024" ], @@ -31,6 +32,7 @@ my @fileList_1024 = ( my @fileList_2048 = ( [ "./certs/client-key.der", "client_key_der_2048" ], + [ "./certs/client-keyPub.der", "client_keypub_der_2048" ], [ "./certs/client-cert.der", "client_cert_der_2048" ], [ "./certs/dh2048.der", "dh_key_der_2048" ], [ "./certs/dsa2048.der", "dsa_key_der_2048" ], @@ -140,6 +142,6 @@ sub file_to_hex { print OUT_FILE "\n"; - close($fp); + close($fp); } diff --git a/src/ssl.c b/src/ssl.c index 30e266011..a09d93c79 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1688,7 +1688,6 @@ int wolfSSL_KeyPemToDer(const unsigned char* pem, int pemSz, return ret; } - #endif /* !NO_CERTS */ @@ -2391,14 +2390,15 @@ int PemToDer(const unsigned char* buff, long longSz, int type, switch (type) { case CA_TYPE: /* same as below */ - case CERT_TYPE: header=BEGIN_CERT; footer=END_CERT; break; - case CRL_TYPE: header=BEGIN_X509_CRL; footer=END_X509_CRL; break; - case DH_PARAM_TYPE: header=BEGIN_DH_PARAM; footer=END_DH_PARAM; break; - case CERTREQ_TYPE: header=BEGIN_CERT_REQ; footer=END_CERT_REQ; break; - case DSA_TYPE: header=BEGIN_DSA_PRIV; footer=END_DSA_PRIV; break; - case ECC_TYPE: header=BEGIN_EC_PRIV; footer=END_EC_PRIV; break; - case RSA_TYPE: header=BEGIN_RSA_PRIV; footer=END_RSA_PRIV; break; - default: header=BEGIN_RSA_PRIV; footer=END_RSA_PRIV; break; + case CERT_TYPE: header=BEGIN_CERT; footer=END_CERT; break; + case CRL_TYPE: header=BEGIN_X509_CRL; footer=END_X509_CRL; break; + case DH_PARAM_TYPE: header=BEGIN_DH_PARAM; footer=END_DH_PARAM; break; + case CERTREQ_TYPE: header=BEGIN_CERT_REQ; footer=END_CERT_REQ; break; + case DSA_TYPE: header=BEGIN_DSA_PRIV; footer=END_DSA_PRIV; break; + case ECC_TYPE: header=BEGIN_EC_PRIV; footer=END_EC_PRIV; break; + case RSA_TYPE: header=BEGIN_RSA_PRIV; footer=END_RSA_PRIV; break; + case PUBLICKEY_TYPE: header=BEGIN_PUB_KEY; footer=END_PUB_KEY; break; + default: header=BEGIN_RSA_PRIV; footer=END_RSA_PRIV; break; } switch (type) { @@ -3968,6 +3968,108 @@ int wolfSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) #endif /* WOLFSSL_CERT_GEN */ +#ifdef WOLFSSL_CERT_EXT +/* load pem public key from file into der buffer, return der size or error */ +int wolfSSL_PemPubKeyToDer(const char* fileName, + unsigned char* derBuf, int derSz) +{ +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force XMALLOC */ +#else + byte staticBuffer[FILE_BUFFER_SIZE]; +#endif + byte* fileBuf = staticBuffer; + int dynamic = 0; + int ret = 0; + long sz = 0; + XFILE file = XFOPEN(fileName, "rb"); + buffer converted; + + WOLFSSL_ENTER("wolfSSL_PemPubKeyToDer"); + + if (file == XBADFILE) + ret = SSL_BAD_FILE; + else { + XFSEEK(file, 0, XSEEK_END); + sz = XFTELL(file); + XREWIND(file); + + if (sz < 0) { + ret = SSL_BAD_FILE; + } + else if (sz > (long)sizeof(staticBuffer)) { + fileBuf = (byte*)XMALLOC(sz, 0, DYNAMIC_TYPE_FILE); + if (fileBuf == NULL) + ret = MEMORY_E; + else + dynamic = 1; + } + + converted.buffer = 0; + + if (ret == 0) { + if ( (ret = (int)XFREAD(fileBuf, sz, 1, file)) < 0) + ret = SSL_BAD_FILE; + else + ret = PemToDer(fileBuf, sz, PUBLICKEY_TYPE, &converted, + 0, NULL, NULL); + + if (ret == 0) { + if (converted.length < (word32)derSz) { + XMEMCPY(derBuf, converted.buffer, converted.length); + ret = converted.length; + } + else + ret = BUFFER_E; + } + + XFREE(converted.buffer, 0, DYNAMIC_TYPE_CA); + } + + XFCLOSE(file); + if (dynamic) + XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE); + } + + return ret; +} + +/* Return bytes written to buff or < 0 for error */ +int wolfSSL_PubKeyPemToDer(const unsigned char* pem, int pemSz, + unsigned char* buff, int buffSz) +{ + int ret; + buffer der; + + WOLFSSL_ENTER("wolfSSL_PubKeyPemToDer"); + + if (pem == NULL || buff == NULL || buffSz <= 0) { + WOLFSSL_MSG("Bad pem der args"); + return BAD_FUNC_ARG; + } + + der.buffer = NULL; + + ret = PemToDer(pem, pemSz, PUBLICKEY_TYPE, &der, NULL, NULL, NULL); + if (ret < 0) { + WOLFSSL_MSG("Bad Pem To Der"); + } + else { + if (der.length <= (word32)buffSz) { + XMEMCPY(buff, der.buffer, der.length); + ret = der.length; + } + else { + WOLFSSL_MSG("Bad der length"); + ret = BAD_FUNC_ARG; + } + } + + XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY); + return ret; +} + +#endif /* WOLFSSL_CERT_EXT */ int wolfSSL_CTX_use_certificate_file(WOLFSSL_CTX* ctx, const char* file, int format) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index cb8cee79c..0f28554e7 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -1444,7 +1444,6 @@ int wc_DsaKeyToDer(DsaKey* key, byte* output, word32 inLen) word32 seqSz, verSz, rawLen, intTotalLen = 0; word32 sizes[DSA_INTS]; int i, j, outLen, ret = 0, lbit; - int err; byte seq[MAX_SEQ_SZ]; byte ver[MAX_VERSION_SZ]; @@ -1645,6 +1644,10 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) cert->extCertPolicyCrit = 0; #endif /* OPENSSL_EXTRA */ #endif /* WOLFSSL_SEP */ +#ifdef WOLFSSL_CERT_EXT + XMEMSET(cert->extCertPolicies, 0, MAX_CERTPOL_NB*MAX_CERTPOL_SZ); + cert->extCertPoliciesNb = 0; +#endif } @@ -4011,12 +4014,9 @@ static int DecodeKeyUsage(byte* input, int sz, DecodedCert* cert) unusedBits = input[idx++]; length--; - if (length == 2) { - cert->extKeyUsage = (word16)((input[idx] << 8) | input[idx+1]); - cert->extKeyUsage >>= unusedBits; - } - else if (length == 1) - cert->extKeyUsage = (word16)(input[idx] << 1); + cert->extKeyUsage = (word16)(input[idx]); + if (length == 2) + cert->extKeyUsage |= (word16)(input[idx+1] << 8); return 0; } @@ -4163,17 +4163,69 @@ static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) } #endif /* IGNORE_NAME_CONSTRAINTS */ +#ifdef WOLFSSL_CERT_EXT +/* Decode ITU-T X.690 OID format to a string representation + * return string length */ +static int DecodePolicyOID(char *out, word32 outSz, byte *in, word32 inSz) +{ + word32 val, idx = 0, nb_bytes; + size_t w_bytes = 0; -#ifdef WOLFSSL_SEP + if (out == NULL || in == NULL || outSz < 4 || inSz < 2) + return BAD_FUNC_ARG; + + /* first two byte must be interpreted as : 40 * int1 + int2 */ + val = (word16)in[idx++]; + + XSNPRINTF(out, outSz, "%d.%d", val / 40, val % 40); + w_bytes += XSTRLEN(out); + + while (idx < inSz) { + /* init value */ + val = 0; + nb_bytes = 0; + + /* check that output size is ok */ + if (w_bytes > (outSz - 3)) + return BUFFER_E; + + /* first bit is used to set if value is coded on 1 or multiple bytes */ + while ((in[idx+nb_bytes] & 0x80)) + nb_bytes++; + + if (!nb_bytes) + val = (word32)(in[idx++] & 0x7f); + else { + word32 base = 1, tmp = nb_bytes; + + while (tmp != 0) { + val += (word32)(in[idx+tmp] & 0x7f) * base; + base *= 128; + tmp--; + } + val += (word32)(in[idx++] & 0x7f) * base; + + idx += nb_bytes; + } + + XSNPRINTF(out+XSTRLEN(out), outSz, ".%d", val); + w_bytes = XSTRLEN(out); + } + + return 0; +} +#endif /* WOLFSSL_CERT_EXT */ + +#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT) static int DecodeCertPolicy(byte* input, int sz, DecodedCert* cert) { word32 idx = 0; - int length = 0; + int total_length = 0, length = 0; WOLFSSL_ENTER("DecodeCertPolicy"); /* Unwrap certificatePolicies */ - if (GetSequence(input, &idx, &length, sz) < 0) { + if (GetSequence(input, &idx, &total_length, sz) < 0) { WOLFSSL_MSG("\tdeviceType isn't OID"); return ASN_PARSE_E; } @@ -4182,11 +4234,13 @@ static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) WOLFSSL_MSG("\tdeviceType isn't OID"); return ASN_PARSE_E; } + total_length -= (length+1); if (input[idx++] != ASN_OBJECT_ID) { WOLFSSL_MSG("\tdeviceType isn't OID"); return ASN_PARSE_E; } + total_length--; if (GetLength(input, &idx, &length, sz) < 0) { WOLFSSL_MSG("\tCouldn't read length of deviceType"); @@ -4194,6 +4248,7 @@ static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) } if (length > 0) { +#if defined(WOLFSSL_SEP) cert->deviceType = (byte*)XMALLOC(length, cert->heap, 0); if (cert->deviceType == NULL) { WOLFSSL_MSG("\tCouldn't alloc memory for deviceType"); @@ -4201,6 +4256,46 @@ static int DecodeNameConstraints(byte* input, int sz, DecodedCert* cert) } cert->deviceTypeSz = length; XMEMCPY(cert->deviceType, input + idx, length); +#elif defined(WOLFSSL_CERT_EXT) + /* decode cert policy */ + if (DecodePolicyOID(cert->extCertPolicies[0], MAX_CERTPOL_SZ, + input+idx, length) != 0) { + WOLFSSL_MSG("\tCouldn't read Policy OID 1"); + return ASN_PARSE_E; + } + cert->extCertPoliciesNb++; + + /* check if we have a second value */ + if (total_length) { + idx += length; + + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (input[idx++] != ASN_OBJECT_ID) { + WOLFSSL_MSG("\tdeviceType isn't OID"); + return ASN_PARSE_E; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tCouldn't read length of deviceType"); + return ASN_PARSE_E; + } + + /* decode cert policy */ + if (DecodePolicyOID(cert->extCertPolicies[1], MAX_CERTPOL_SZ, + input+idx, length) != 0) { + WOLFSSL_MSG("\tCouldn't read Policy OID 2"); + return ASN_PARSE_E; + } + cert->extCertPoliciesNb++; + } +#else + WOLFSSL_LEAVE("DecodeCertPolicy : unsupported mode", 0); + return 0; +#endif } WOLFSSL_LEAVE("DecodeCertPolicy", 0); @@ -4228,14 +4323,20 @@ static int DecodeCertExtensions(DecodedCert* cert) if (input == NULL || sz == 0) return BAD_FUNC_ARG; - if (input[idx++] != ASN_EXTENSIONS) + if (input[idx++] != ASN_EXTENSIONS) { + WOLFSSL_MSG("\tfail: should be an EXTENSIONS"); return ASN_PARSE_E; + } - if (GetLength(input, &idx, &length, sz) < 0) + if (GetLength(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: invalid length"); return ASN_PARSE_E; + } - if (GetSequence(input, &idx, &length, sz) < 0) + if (GetSequence(input, &idx, &length, sz) < 0) { + WOLFSSL_MSG("\tfail: should be a SEQUENCE (1)"); return ASN_PARSE_E; + } while (idx < (word32)sz) { if (GetSequence(input, &idx, &length, sz) < 0) { @@ -4327,8 +4428,10 @@ static int DecodeCertExtensions(DecodedCert* cert) cert->extCertPolicySet = 1; cert->extCertPolicyCrit = critical; #endif - if (DecodeCertPolicy(&input[idx], length, cert) < 0) - return ASN_PARSE_E; + #endif + #if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT) + if (DecodeCertPolicy(&input[idx], length, cert) < 0) + return ASN_PARSE_E; #endif break; @@ -4672,6 +4775,8 @@ const char* BEGIN_EC_PRIV = "-----BEGIN EC PRIVATE KEY-----"; const char* END_EC_PRIV = "-----END EC PRIVATE KEY-----"; const char* BEGIN_DSA_PRIV = "-----BEGIN DSA PRIVATE KEY-----"; const char* END_DSA_PRIV = "-----END DSA PRIVATE KEY-----"; +const char* BEGIN_PUB_KEY = "-----BEGIN PUBLIC KEY-----"; +const char* END_PUB_KEY = "-----END PUBLIC KEY-----"; #if defined(WOLFSSL_KEY_GEN) || defined(WOLFSSL_CERT_GEN) @@ -5000,6 +5105,15 @@ void wc_InitCert(Cert* cert) cert->altNamesSz = 0; cert->beforeDateSz = 0; cert->afterDateSz = 0; +#endif +#ifdef WOLFSSL_CERT_EXT + cert->skidSz = 0; + cert->akidSz = 0; + cert->keyUsage = 0; + cert->certPoliciesNb = 0; + XMEMSET(cert->akid, 0, CTC_MAX_AKID_SIZE); + XMEMSET(cert->skid, 0, CTC_MAX_SKID_SIZE); + XMEMSET(cert->certPolicies, 0, CTC_MAX_CERTPOL_NB*CTC_MAX_CERTPOL_SZ); #endif cert->keyType = RSA_KEY; XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE); @@ -5053,9 +5167,18 @@ typedef struct DerCert { byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2]; /* before and after dates */ byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */ byte ca[MAX_CA_SZ]; /* basic constraint CA true size */ - byte extensions[MAX_EXTENSIONS_SZ]; /* all extensions */ + byte extensions[MAX_EXTENSIONS_SZ]; /* all extensions */ +#ifdef WOLFSSL_CERT_EXT + byte skid[MAX_KID_SZ]; /* Subject Key Identifier extension */ + byte akid[MAX_KID_SZ]; /* Authority Key Identifier extension */ + byte keyUsage[MAX_KEYUSAGE_SZ]; /* Key Usage extension */ + byte certPolicies[MAX_CERTPOL_NB*MAX_CERTPOL_SZ]; /* Certificate Policies */ +#endif #ifdef WOLFSSL_CERT_REQ byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */ +#endif +#ifdef WOLFSSL_ALT_NAMES + byte altNames[CTC_MAX_ALT_SIZE]; /* Alternative Names encoded */ #endif int sizeSz; /* encoded size length */ int versionSz; /* encoded version length */ @@ -5066,6 +5189,15 @@ typedef struct DerCert { int validitySz; /* encoded validity length */ int publicKeySz; /* encoded public key length */ int caSz; /* encoded CA extension length */ +#ifdef WOLFSSL_CERT_EXT + int skidSz; /* encoded SKID extension length */ + int akidSz; /* encoded SKID extension length */ + int keyUsageSz; /* encoded KeyUsage extension length */ + int certPoliciesSz; /* encoded CertPolicies extension length*/ +#endif +#ifdef WOLFSSL_ALT_NAMES + int altNamesSz; /* encoded AltNames extension length */ +#endif int extensionsSz; /* encoded extensions total length */ int total; /* total encoded lengths */ #ifdef WOLFSSL_CERT_REQ @@ -5103,7 +5235,7 @@ static int SetSerial(const byte* serial, byte* output) /* Write a public ECC key to output */ -static int SetEccPublicKey(byte* output, ecc_key* key) +static int SetEccPublicKey(byte* output, ecc_key* key, int with_header) { byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ int algoSz; @@ -5135,58 +5267,63 @@ static int SetEccPublicKey(byte* output, ecc_key* key) return ret; } -#ifdef WOLFSSL_SMALL_STACK - curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (curve == NULL) { - XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - /* headers */ - curveSz = SetCurve(key, curve); - if (curveSz <= 0) { + if (with_header) { #ifdef WOLFSSL_SMALL_STACK - XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); + curve = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (curve == NULL) { + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } #endif - return curveSz; - } + curveSz = SetCurve(key, curve); + if (curveSz <= 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return curveSz; + } #ifdef WOLFSSL_SMALL_STACK - algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (algo == NULL) { - XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } + algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (algo == NULL) { + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } #endif + algoSz = SetAlgoID(ECDSAk, algo, keyType, curveSz); - algoSz = SetAlgoID(ECDSAk, algo, keyType, curveSz); - lenSz = SetLength(pubSz + 1, len); - len[lenSz++] = 0; /* trailing 0 */ + lenSz = SetLength(pubSz + 1, len); + len[lenSz++] = 0; /* trailing 0 */ + + /* write, 1 is for ASN_BIT_STRING */ + idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output); + /* algo */ + XMEMCPY(output + idx, algo, algoSz); + idx += algoSz; + /* curve */ + XMEMCPY(output + idx, curve, curveSz); + idx += curveSz; + /* bit string */ + output[idx++] = ASN_BIT_STRING; + /* length */ + XMEMCPY(output + idx, len, lenSz); + idx += lenSz; + } + else + idx = 0; - /* write */ - idx = SetSequence(pubSz + curveSz + lenSz + 1 + algoSz, output); - /* 1 is for ASN_BIT_STRING */ - /* algo */ - XMEMCPY(output + idx, algo, algoSz); - idx += algoSz; - /* curve */ - XMEMCPY(output + idx, curve, curveSz); - idx += curveSz; - /* bit string */ - output[idx++] = ASN_BIT_STRING; - /* length */ - XMEMCPY(output + idx, len, lenSz); - idx += lenSz; /* pub */ XMEMCPY(output + idx, pub, pubSz); idx += pubSz; #ifdef WOLFSSL_SMALL_STACK - XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (with_header) { + XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(curve, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -5198,7 +5335,7 @@ static int SetEccPublicKey(byte* output, ecc_key* key) /* Write a public RSA key to output */ -static int SetRsaPublicKey(byte* output, RsaKey* key) +static int SetRsaPublicKey(byte* output, RsaKey* key, int with_header) { #ifdef WOLFSSL_SMALL_STACK byte* n = NULL; @@ -5292,31 +5429,39 @@ static int SetRsaPublicKey(byte* output, RsaKey* key) } #ifdef WOLFSSL_SMALL_STACK - algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (algo == NULL) { - XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; + if (with_header) { + algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (algo == NULL) { + XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } } #endif - /* headers */ - algoSz = SetAlgoID(RSAk, algo, keyType, 0); seqSz = SetSequence(nSz + eSz, seq); - lenSz = SetLength(seqSz + nSz + eSz + 1, len); - len[lenSz++] = 0; /* trailing 0 */ - /* write */ - idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output); - /* 1 is for ASN_BIT_STRING */ - /* algo */ - XMEMCPY(output + idx, algo, algoSz); - idx += algoSz; - /* bit string */ - output[idx++] = ASN_BIT_STRING; - /* length */ - XMEMCPY(output + idx, len, lenSz); - idx += lenSz; + /* headers */ + if (with_header) { + algoSz = SetAlgoID(RSAk, algo, keyType, 0); + lenSz = SetLength(seqSz + nSz + eSz + 1, len); + len[lenSz++] = 0; /* trailing 0 */ + + /* write */ + idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output); + /* 1 is for ASN_BIT_STRING */ + /* algo */ + XMEMCPY(output + idx, algo, algoSz); + idx += algoSz; + /* bit string */ + output[idx++] = ASN_BIT_STRING; + /* length */ + XMEMCPY(output + idx, len, lenSz); + idx += lenSz; + } + else + idx = 0; + /* seq */ XMEMCPY(output + idx, seq, seqSz); idx += seqSz; @@ -5330,7 +5475,8 @@ static int SetRsaPublicKey(byte* output, RsaKey* key) #ifdef WOLFSSL_SMALL_STACK XFREE(n, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(e, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (with_header) + XFREE(algo, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return idx; @@ -5583,29 +5729,51 @@ static byte GetNameId(int idx) } } +/* + Extensions ::= SEQUENCE OF Extension + + Extension ::= SEQUENCE { + extnId OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING } + */ /* encode all extensions, return total bytes written */ -static int SetExtensions(byte* output, const byte* ext, int extSz, int header) +static int SetExtensions(byte* output, int *IdxInOut, + const byte* ext, int extSz) +{ + if (output == NULL || IdxInOut == NULL || ext == NULL) + return BAD_FUNC_ARG; + + XMEMCPY(&output[*IdxInOut], ext, extSz); /* extensions */ + *IdxInOut += extSz; + + return *IdxInOut; +} + +/* encode extensions header, return total bytes written */ +static int SetExtensionsHeader(byte* output, int extSz) { byte sequence[MAX_SEQ_SZ]; byte len[MAX_LENGTH_SZ]; + int seqSz, lenSz, idx = 0; - int sz = 0; - int seqSz = SetSequence(extSz, sequence); + if (output == NULL) + return BAD_FUNC_ARG; - if (header) { - int lenSz = SetLength(seqSz + extSz, len); - output[0] = ASN_EXTENSIONS; /* extensions id */ - sz++; - XMEMCPY(&output[sz], len, lenSz); /* length */ - sz += lenSz; - } - XMEMCPY(&output[sz], sequence, seqSz); /* sequence */ - sz += seqSz; - XMEMCPY(&output[sz], ext, extSz); /* extensions */ - sz += extSz; + seqSz = SetSequence(extSz, sequence); - return sz; + /* encode extensions length provided */ + lenSz = SetLength(extSz+seqSz, len); + + output[idx++] = ASN_EXTENSIONS; /* extensions id */ + XMEMCPY(&output[idx], len, lenSz); /* length */ + idx += lenSz; + + XMEMCPY(&output[idx], sequence, seqSz); /* sequence */ + idx += seqSz; + + return idx; } @@ -5621,6 +5789,289 @@ static int SetCa(byte* output) } +#ifdef WOLFSSL_CERT_EXT +/* encode OID and associated value, return total bytes written */ +static int SetOidValue(byte* out, const byte *oid, word32 oidSz, + byte *in, word32 inSz) +{ + int idx = 0; + + if (out == NULL || oid == NULL || in == NULL) + return BAD_FUNC_ARG; + + /* sequence, + 1 => byte to put value size */ + idx = SetSequence(inSz + oidSz + 1, out); + + XMEMCPY(out+idx, oid, oidSz); + idx += oidSz; + out[idx++] = (byte)inSz; + XMEMCPY(out+idx, in, inSz); + + return (idx+inSz); +} + +/* encode Subject Key Identifier, return total bytes written + * RFC5280 : non-critical */ +static int SetSKID(byte* output, byte *input, word32 length) +{ + byte skid_len[MAX_LENGTH_SZ]; + byte skid_enc_len[MAX_LENGTH_SZ]; + int idx = 0, skid_lenSz, skid_enc_lenSz; + static const byte skid_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04 }; + + if (output == NULL || input == NULL) + return BAD_FUNC_ARG; + + /* length of value */ + skid_lenSz = SetLength(length, skid_len); + + /* length of encoded value */ + skid_enc_lenSz = SetLength(length + skid_lenSz + 1, skid_enc_len); + + /* sequence, + 1 => byte to put type size */ + idx = SetSequence(length + sizeof(skid_oid) + skid_lenSz + skid_enc_lenSz+1, + output); + + /* put oid */ + XMEMCPY(output+idx, skid_oid, sizeof(skid_oid)); + idx += sizeof(skid_oid); + + /* put encoded len */ + XMEMCPY(output+idx, skid_enc_len, skid_enc_lenSz); + idx += skid_enc_lenSz; + + /* put type */ + output[idx++] = ASN_OCTET_STRING; + + /* put value len */ + XMEMCPY(output+idx, skid_len, skid_lenSz); + idx += skid_lenSz; + + /* put value */ + XMEMCPY(output+idx, input, length); + idx += length; + + return idx; +} + +/* encode Authority Key Identifier, return total bytes written + * RFC5280 : non-critical */ +static int SetAKID(byte* output, byte *input, word32 length) +{ + byte *enc_val; + int ret, enc_valSz; + static const byte akid_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04}; + static const byte akid_cs[] = { 0x80 }; + + if (output == NULL || input == NULL) + return BAD_FUNC_ARG; + + enc_val = (byte *)XMALLOC(length+3+sizeof(akid_cs), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (enc_val == NULL) + return MEMORY_E; + + /* sequence for ContentSpec & value */ + enc_valSz = SetOidValue(enc_val, akid_cs, sizeof(akid_cs), input, length); + if (enc_valSz == 0) { + XFREE(enc_val, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; + } + + ret = SetOidValue(output, akid_oid, sizeof(akid_oid), enc_val, enc_valSz); + + XFREE(enc_val, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +/* encode Key Usage, return total bytes written + * RFC5280 : critical */ +static int SetKeyUsage(byte* output, word16 input) +{ + byte ku[5]; + int unusedBits = 0; + static const byte keyusage_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04}; + + if (output == NULL) + return BAD_FUNC_ARG; + + /* Key Usage is a BitString */ + ku[0] = ASN_BIT_STRING; + + /* put the Bit String size */ + if (input > 255) { + ku[1] = (byte)3; + + /* compute unused bits */ + while (((((input >> 8) & 0xff) >> unusedBits) & 0x01) == 0) + unusedBits++; + } + else { + ku[1] = (byte)2; + + /* compute unused bits */ + while (((input >> unusedBits) & 0x01) == 0) + unusedBits++; + } + + /* put unused bits value */ + ku[2] = (byte)unusedBits; + + /* compute byte value */ + ku[3] = (byte)(input & 0xff); + if (input > 255) + ku[4] = (byte)((input >> 8) & 0xff); + + return SetOidValue(output, keyusage_oid, sizeof(keyusage_oid), + ku, (int)ku[1]+2); +} + +/* Encode OID string representation to ITU-T X.690 format */ +static int EncodePolicyOID(byte *out, word32 *outSz, const char *in) +{ + word32 val, idx = 0, nb_val; + char *token, *str; + word32 len; + + if (out == NULL || outSz == NULL || *outSz < 2 || in == NULL) + return BAD_FUNC_ARG; + + len = (word32)XSTRLEN(in); + + str = (char *)XMALLOC(len+1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) + return MEMORY_E; + + XSTRNCPY(str, in, len); + str[len] = 0x00; + + nb_val = 0; + + /* parse value, and set corresponding Policy OID value */ + while ((token = strsep(&str, ".")) != NULL) + { + val = (word32)atoi(token); + + if (nb_val == 0) { + if (val > 2) { + XFREE(str, NUL, DYNAMIC_TYPE_TMP_BUFFER); + return ASN_OBJECT_ID_E; + } + + out[idx] = (byte)(40 * val); + } + else if (nb_val == 1) { + if (val > 127) { + XFREE(str, NUL, DYNAMIC_TYPE_TMP_BUFFER); + return ASN_OBJECT_ID_E; + } + + if (idx > *outSz) { + XFREE(str, NUL, DYNAMIC_TYPE_TMP_BUFFER); + return BUFFER_E; + } + + out[idx++] += (byte)val; + } + else { + word32 tb = 0, x; + int i = 0; + byte oid[MAX_OID_SZ]; + + while (val >= 128) { + x = val % 128; + val /= 128; + oid[i++] = (byte) (((tb++) ? 0x80 : 0) | x); + } + + if ((idx+(word32)i) > *outSz) { + XFREE(str, NUL, DYNAMIC_TYPE_TMP_BUFFER); + return BUFFER_E; + } + + oid[i] = (byte) (((tb++) ? 0x80 : 0) | val); + + /* push value in the right order */ + while (i >= 0) + out[idx++] = oid[i--]; + } + + nb_val++; + } + + *outSz = idx; + + XFREE(str, NUL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; +} + +/* encode Certificate Policies, return total bytes written + * each input value must be ITU-T X.690 formatted : a.b.c... + * input must be an array of values with a NULL terminated for the latest + * RFC5280 : non-critical */ +static int SetCertificatePolicies(byte *output, + char input[MAX_CERTPOL_NB][MAX_CERTPOL_SZ], + word16 nb_certpol) +{ + byte oid[MAX_OID_SZ], + der_oid[MAX_CERTPOL_NB][MAX_OID_SZ], + out[MAX_CERTPOL_SZ]; + word32 oidSz; + word32 outSz, i = 0, der_oidSz[MAX_CERTPOL_NB]; + int ret; + + static const byte certpol_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04 }; + static const byte oid_oid[] = { 0x06 }; + + if (output == NULL || input == NULL || nb_certpol > MAX_CERTPOL_NB) + return BAD_FUNC_ARG; + + for (i = 0; i < nb_certpol; i++) { + oidSz = sizeof(oid); + memset(oid, 0, oidSz); + + ret = EncodePolicyOID(oid, &oidSz, input[i]); + if (ret != 0) + return ret; + + /* compute sequence value for the oid */ + ret = SetOidValue(der_oid[i], oid_oid, sizeof(oid_oid), oid, oidSz); + if (ret <= 0) + return ret; + else + der_oidSz[i] = (word32)ret; + } + + /* concatene oid, keep two byte for sequence/size of the created value */ + for (i = 0, outSz = 2; i < nb_certpol; i++) { + XMEMCPY(out+outSz, der_oid[i], der_oidSz[i]); + outSz += der_oidSz[i]; + } + + /* add sequence */ + ret = SetSequence(outSz-2, out); + if (ret <= 0) + return ret; + + /* add Policy OID to compute final value */ + return SetOidValue(output, certpol_oid, sizeof(certpol_oid), + out, outSz); +} +#endif /* WOLFSSL_CERT_EXT */ + +#ifdef WOLFSSL_ALT_NAMES +/* encode Alternative Names, return total bytes written */ +static int SetAltNames(byte *output, byte *input, word32 length) +{ + /* Alternative Names come from certificate or computed by + * external function, so already encoded. Just copy value */ + XMEMCPY(output, input, length); + return length; +} +#endif /* WOLFSL_ALT_NAMES */ + + /* encode CertName into output, return total bytes written */ static int SetName(byte* output, CertName* name) { @@ -5787,7 +6238,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, if (cert->keyType == RSA_KEY) { if (rsaKey == NULL) return PUBLIC_KEY_E; - der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); + der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey, 1); if (der->publicKeySz <= 0) return PUBLIC_KEY_E; } @@ -5796,7 +6247,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, if (cert->keyType == ECC_KEY) { if (eccKey == NULL) return PUBLIC_KEY_E; - der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); + der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey, 1); if (der->publicKeySz <= 0) return PUBLIC_KEY_E; } @@ -5851,34 +6302,152 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, if (der->issuerSz == 0) return ISSUER_E; + /* set the extensions */ + der->extensionsSz = 0; + /* CA */ if (cert->isCA) { der->caSz = SetCa(der->ca); if (der->caSz == 0) return CA_TRUE_E; + + der->extensionsSz += der->caSz; } else der->caSz = 0; - /* extensions, just CA now */ - if (cert->isCA) { - der->extensionsSz = SetExtensions(der->extensions, - der->ca, der->caSz, TRUE); - if (der->extensionsSz == 0) - return EXTENSIONS_E; +#ifdef WOLFSSL_ALT_NAMES + /* Alternative Name */ + if (cert->altNamesSz) { + der->altNamesSz = SetAltNames(der->altNames, + cert->altNames, cert->altNamesSz); + if (der->altNamesSz == 0) + return ALT_NAME_E; + + der->extensionsSz += der->altNamesSz; } else - der->extensionsSz = 0; + der->altNamesSz = 0; +#endif -#ifdef WOLFSSL_ALT_NAMES - if (der->extensionsSz == 0 && cert->altNamesSz) { - der->extensionsSz = SetExtensions(der->extensions, cert->altNames, - cert->altNamesSz, TRUE); +#ifdef WOLFSSL_CERT_EXT + /* SKID */ + if (cert->skidSz) { + /* check the provided SKID size */ + if (cert->skidSz > (int)sizeof(der->skid)) + return SKID_E; + + der->skidSz = SetSKID(der->skid, cert->skid, cert->skidSz); + if (der->skidSz == 0) + return SKID_E; + + der->extensionsSz += der->skidSz; + } + else + der->skidSz = 0; + + /* AKID */ + if (cert->akidSz) { + /* check the provided AKID size */ + if (cert->akidSz > (int)sizeof(der->akid)) + return AKID_E; + + der->akidSz = SetAKID(der->akid, cert->akid, cert->akidSz); + if (der->akidSz == 0) + return AKID_E; + + der->extensionsSz += der->akidSz; + } + else + der->akidSz = 0; + + /* Key Usage */ + if (cert->keyUsage != 0){ + der->keyUsageSz = SetKeyUsage(der->keyUsage, cert->keyUsage); + if (der->keyUsageSz == 0) + return KEYUSAGE_E; + + der->extensionsSz += der->keyUsageSz; + } + else + der->keyUsageSz = 0; + + /* Certificate Policies */ + if (cert->certPoliciesNb != 0) { + der->certPoliciesSz = SetCertificatePolicies(der->certPolicies, + cert->certPolicies, + cert->certPoliciesNb); + if (der->certPoliciesSz == 0) + return CERTPOLICIES_E; + + der->extensionsSz += der->certPoliciesSz; + } + else + der->certPoliciesSz = 0; +#endif /* WOLFSSL_CERT_EXT */ + + /* put extensions */ + if (der->extensionsSz > 0) { + + /* put the start of extensions sequence (ID, Size) */ + der->extensionsSz = SetExtensionsHeader(der->extensions, + der->extensionsSz); if (der->extensionsSz == 0) return EXTENSIONS_E; - } + + /* put CA */ + if (der->caSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->ca, der->caSz); + if (ret == 0) + return EXTENSIONS_E; + } + +#ifdef WOLFSSL_ALT_NAMES + /* put Alternative Names */ + if (der->altNamesSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->altNames, der->altNamesSz); + if (ret == 0) + return EXTENSIONS_E; + } #endif +#ifdef WOLFSSL_CERT_EXT + /* put SKID */ + if (der->skidSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->skid, der->skidSz); + if (ret == 0) + return EXTENSIONS_E; + } + + /* put AKID */ + if (der->akidSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->akid, der->akidSz); + if (ret == 0) + return EXTENSIONS_E; + } + + /* put KeyUsage */ + if (der->keyUsageSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->keyUsage, der->keyUsageSz); + if (ret == 0) + return EXTENSIONS_E; + } + + /* put Certificate Policies */ + if (der->certPoliciesSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->certPolicies, der->certPoliciesSz); + if (ret == 0) + return EXTENSIONS_E; + } +#endif /* WOLFSSL_CERT_EXT */ + } + der->total = der->versionSz + der->serialSz + der->sigAlgoSz + der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz + der->extensionsSz; @@ -6072,7 +6641,6 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, #endif ret = EncodeCert(cert, der, rsaKey, eccKey, rng, ntruKey, ntruSz); - if (ret == 0) { if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) ret = BUFFER_E; @@ -6201,7 +6769,7 @@ static int EncodeCertReq(Cert* cert, DerCert* der, if (cert->keyType == RSA_KEY) { if (rsaKey == NULL) return PUBLIC_KEY_E; - der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey); + der->publicKeySz = SetRsaPublicKey(der->publicKey, rsaKey, 1); if (der->publicKeySz <= 0) return PUBLIC_KEY_E; } @@ -6210,30 +6778,98 @@ static int EncodeCertReq(Cert* cert, DerCert* der, if (cert->keyType == ECC_KEY) { if (eccKey == NULL) return PUBLIC_KEY_E; - der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey); + der->publicKeySz = SetEccPublicKey(der->publicKey, eccKey, 1); if (der->publicKeySz <= 0) return PUBLIC_KEY_E; } #endif /* HAVE_ECC */ + /* set the extensions */ + der->extensionsSz = 0; + /* CA */ if (cert->isCA) { der->caSz = SetCa(der->ca); if (der->caSz == 0) return CA_TRUE_E; + + der->extensionsSz += der->caSz; } else der->caSz = 0; - /* extensions, just CA now */ - if (cert->isCA) { - der->extensionsSz = SetExtensions(der->extensions, - der->ca, der->caSz, FALSE); - if (der->extensionsSz == 0) - return EXTENSIONS_E; +#ifdef WOLFSSL_CERT_EXT + /* SKID */ + if (cert->skidSz) { + /* check the provided SKID size */ + if (cert->skidSz > (int)sizeof(der->skid)) + return SKID_E; + + der->skidSz = SetSKID(der->skid, cert->skid, cert->skidSz); + if (der->skidSz == 0) + return SKID_E; + + der->extensionsSz += der->skidSz; } else - der->extensionsSz = 0; + der->skidSz = 0; + + /* Key Usage */ + if (cert->keyUsage != 0){ + der->keyUsageSz = SetKeyUsage(der->keyUsage, cert->keyUsage); + if (der->keyUsageSz == 0) + return KEYUSAGE_E; + + der->extensionsSz += der->keyUsageSz; + } + else + der->keyUsageSz = 0; +#endif /* WOLFSSL_CERT_EXT */ + + /* put extensions */ + if (der->extensionsSz > 0) { + int ret; + + /* put the start of sequence (ID, Size) */ + der->extensionsSz = SetSequence(der->extensionsSz, der->extensions); + if (der->extensionsSz == 0) + return EXTENSIONS_E; + + /* put CA */ + if (der->caSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->ca, der->caSz); + if (ret == 0) + return EXTENSIONS_E; + } + +#ifdef WOLFSSL_CERT_EXT + /* put SKID */ + if (der->skidSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->skid, der->skidSz); + if (ret == 0) + return EXTENSIONS_E; + } + + /* put AKID */ + if (der->akidSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->akid, der->akidSz); + if (ret == 0) + return EXTENSIONS_E; + } + + /* put KeyUsage */ + if (der->keyUsageSz) { + ret = SetExtensions(der->extensions, &der->extensionsSz, + der->keyUsage, der->keyUsageSz); + if (ret == 0) + return EXTENSIONS_E; + } + +#endif /* WOLFSSL_CERT_EXT */ + } der->attribSz = SetReqAttrib(der->attrib, cert->challengePw, der->extensionsSz); @@ -6354,8 +6990,9 @@ int wc_SignCert(int requestSz, int sType, byte* buffer, word32 buffSz, int wc_MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, WC_RNG* rng) { - int ret = wc_MakeCert(cert, buffer, buffSz, key, NULL, rng); + int ret; + ret = wc_MakeCert(cert, buffer, buffSz, key, NULL, rng); if (ret < 0) return ret; @@ -6364,6 +7001,321 @@ int wc_MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, } +#ifdef WOLFSSL_CERT_EXT + +/* Set KID from RSA or ECC public key */ +static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, + byte *ntruKey, word16 ntruKeySz, int kid_type) +{ + byte *buffer; + int bufferSz, ret; + +#ifndef HAVE_NTRU + (void)ntruKeySz; +#endif + + if (cert == NULL || (rsakey == NULL && eckey == NULL && ntruKey == NULL) || + (rsakey != NULL && eckey != NULL) || + (rsakey != NULL && ntruKey != NULL) || + (ntruKey != NULL && eckey != NULL) || + (kid_type != SKID_TYPE && kid_type != AKID_TYPE)) + return BAD_FUNC_ARG; + + buffer = (byte *)XMALLOC(MAX_PUBLIC_KEY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buffer == NULL) + return MEMORY_E; + + /* RSA public key */ + if (rsakey != NULL) + bufferSz = SetRsaPublicKey(buffer, rsakey, 0); +#ifdef HAVE_ECC + /* ECC public key */ + else if (eckey != NULL) + bufferSz = SetEccPublicKey(buffer, eckey, 0); +#endif /* HAVE_ECC */ +#ifdef HAVE_NTRU + /* NTRU public key */ + else if (ntruKey != NULL) { + bufferSz = MAX_PUBLIC_KEY_SZ; + ret = ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( + ntruKeySz, ntruKey, (word16 *)(&bufferSz), buffer); + if (ret != NTRU_OK) + bufferSz = -1; + } +#endif + else + bufferSz = -1; + + if (bufferSz <= 0) { + XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PUBLIC_KEY_E; + } + + /* Compute SKID by hashing public key */ +#ifdef NO_SHA + if (kid_type == SKID_TYPE) { + ret = wc_Sha256Hash(buffer, bufferSz, cert->skid); + cert->skidSz = SHA256_DIGEST_SIZE; + } + else if (kid_type == AKID_TYPE) { + ret = wc_Sha256Hash(buffer, bufferSz, cert->akid); + cert->akidSz = SHA256_DIGEST_SIZE; + } + else + ret = BAD_FUNC_ARG; +#else /* NO_SHA */ + if (kid_type == SKID_TYPE) { + ret = wc_ShaHash(buffer, bufferSz, cert->skid); + cert->skidSz = SHA_DIGEST_SIZE; + } + else if (kid_type == AKID_TYPE) { + ret = wc_ShaHash(buffer, bufferSz, cert->akid); + cert->akidSz = SHA_DIGEST_SIZE; + } + else + ret = BAD_FUNC_ARG; +#endif /* NO_SHA */ + + XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +/* Set SKID from RSA or ECC public key */ +int wc_SetSubjectKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey) +{ + return SetKeyIdFromPublicKey(cert, rsakey, eckey, NULL, 0, SKID_TYPE); +} + +#ifdef HAVE_NTRU +/* Set SKID from NTRU public key */ +int wc_SetSubjectKeyIdFromNtruPublicKey(Cert *cert, + byte *ntruKey, word16 ntruKeySz) +{ + return SetKeyIdFromPublicKey(cert, NULL,NULL,ntruKey, ntruKeySz, SKID_TYPE); +} +#endif + +/* Set SKID from RSA or ECC public key */ +int wc_SetAuthKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey) +{ + return SetKeyIdFromPublicKey(cert, rsakey, eckey, NULL, 0, AKID_TYPE); +} + + +/* Set SKID from public key file in PEM */ +int wc_SetSubjectKeyId(Cert *cert, const char* file) +{ + int ret, derSz; + byte* der; + word32 idx; + RsaKey *rsakey = NULL; + ecc_key *eckey = NULL; + + if (cert == NULL || file == NULL) + return BAD_FUNC_ARG; + + der = (byte*)XMALLOC(MAX_PUBLIC_KEY_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + WOLFSSL_MSG("wc_SetSubjectKeyId memory Problem"); + return MEMORY_E; + } + + derSz = wolfSSL_PemPubKeyToDer(file, der, MAX_PUBLIC_KEY_SZ); + if (derSz <= 0) + { + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + return derSz; + } + + /* Load PubKey in internal structure */ + rsakey = (RsaKey*) XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (rsakey == NULL) { + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + if (wc_InitRsaKey(rsakey, NULL) != 0) { + WOLFSSL_MSG("wc_InitRsaKey failure"); + XFREE(rsakey, NULL, DYNAMIC_TYPE_RSA); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + idx = 0; + ret = wc_RsaPublicKeyDecode(der, &idx, rsakey, derSz); + if (ret != 0) { + WOLFSSL_MSG("wc_RsaPublicKeyDecode failed"); + wc_FreeRsaKey(rsakey); + XFREE(rsakey, NULL, DYNAMIC_TYPE_RSA); + rsakey = NULL; + + /* Check to load ecc public key */ + eckey = (ecc_key*) XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); + if (eckey == NULL) { + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + if (wc_ecc_init(eckey) != 0) { + WOLFSSL_MSG("wc_ecc_init failure"); + wc_ecc_free(eckey); + XFREE(eckey, NULL, DYNAMIC_TYPE_ECC); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + idx = 0; + ret = wc_EccPublicKeyDecode(der, &idx, eckey, derSz); + if (ret != 0) { + WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wc_ecc_free(eckey); + return PUBLIC_KEY_E; + } + } + + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + ret = wc_SetSubjectKeyIdFromPublicKey(cert, rsakey, eckey); + + wc_FreeRsaKey(rsakey); + XFREE(rsakey, NULL, DYNAMIC_TYPE_RSA); + wc_ecc_free(eckey); + XFREE(eckey, NULL, DYNAMIC_TYPE_ECC); + + return ret; +} + +/* Set AKID from certificate contains in buffer (DER encoded) */ +int wc_SetAuthKeyIdFromCert(Cert *cert, const byte *der, int derSz) +{ + int ret; + +#ifdef WOLFSSL_SMALL_STACK + DecodedCert* decoded; +#else + DecodedCert decoded[1]; +#endif + + if (cert == NULL || der == NULL || derSz <= 0) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (decoded == NULL) + return MEMORY_E; +#endif + + /* decode certificate and get SKID that will be AKID of current cert */ + InitDecodedCert(decoded, (byte*)der, derSz, 0); + ret = ParseCert(decoded, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) { + FreeDecodedCert(decoded); + return ret; + } + + /* Subject Key Id not found !! */ + if (decoded->extSubjKeyIdSet == 0) { + FreeDecodedCert(decoded); + return ASN_NO_SKID; + } + + /* SKID invalid size */ + if (sizeof(cert->akid) < sizeof(decoded->extSubjKeyId)) { + FreeDecodedCert(decoded); + return MEMORY_E; + } + + /* Put the SKID of CA to AKID of certificate */ + XMEMCPY(cert->akid, decoded->extSubjKeyId, KEYID_SIZE); + cert->akidSz = KEYID_SIZE; + + FreeDecodedCert(decoded); + return 0; +} + +/* Set AKID from certificate file in PEM */ +int wc_SetAuthKeyId(Cert *cert, const char* file) +{ + int ret; + int derSz; + byte* der; + + if (cert == NULL || file == NULL) + return BAD_FUNC_ARG; + + der = (byte*)XMALLOC(EIGHTK_BUF, NULL, DYNAMIC_TYPE_CERT); + if (der == NULL) { + WOLFSSL_MSG("wc_SetAuthKeyId OOF Problem"); + return MEMORY_E; + } + + derSz = wolfSSL_PemCertToDer(file, der, EIGHTK_BUF); + if (derSz <= 0) + { + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + return derSz; + } + + ret = wc_SetAuthKeyIdFromCert(cert, der, derSz); + XFREE(der, NULL, DYNAMIC_TYPE_CERT); + + return ret; +} + +/* Set KeyUsage from human readale string */ +int wc_SetKeyUsage(Cert *cert, const char *value) +{ + char *token, *str; + word32 len; + + if (cert == NULL || value == NULL) + return BAD_FUNC_ARG; + + cert->keyUsage = 0; + + str = (char *)XMALLOC(XSTRLEN(value)+1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (str == NULL) + return MEMORY_E; + + XMEMSET(str, 0, XSTRLEN(value)+1); + XSTRNCPY(str, value, XSTRLEN(value)); + + /* parse value, and set corresponding Key Usage value */ + while ((token = strsep(&str, ",")) != NULL) + { + len = (word32)XSTRLEN(token); + + if (!XSTRNCASECMP(token, "digitalSignature", len)) + cert->keyUsage |= KEYUSE_DIGITAL_SIG; + else if (!XSTRNCASECMP(token, "nonRepudiation", len) || + !XSTRNCASECMP(token, "contentCommitment", len)) + cert->keyUsage |= KEYUSE_CONTENT_COMMIT; + else if (!XSTRNCASECMP(token, "keyEncipherment", len)) + cert->keyUsage |= KEYUSE_KEY_ENCIPHER; + else if (!XSTRNCASECMP(token, "dataEncipherment", len)) + cert->keyUsage |= KEYUSE_DATA_ENCIPHER; + else if (!XSTRNCASECMP(token, "keyAgreement", len)) + cert->keyUsage |= KEYUSE_KEY_AGREE; + else if (!XSTRNCASECMP(token, "keyCertSign", len)) + cert->keyUsage |= KEYUSE_KEY_CERT_SIGN; + else if (!XSTRNCASECMP(token, "cRLSign", len)) + cert->keyUsage |= KEYUSE_CRL_SIGN; + else if (!XSTRNCASECMP(token, "encipherOnly", len)) + cert->keyUsage |= KEYUSE_ENCIPHER_ONLY; + else if (!XSTRNCASECMP(token, "decipherOnly", len)) + cert->keyUsage |= KEYUSE_DECIPHER_ONLY; + else + return KEYUSAGE_E; + } + + XFREE(str, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return 0; +} +#endif /* WOLFSSL_CERT_EXT */ + + #ifdef WOLFSSL_ALT_NAMES /* Set Alt Names from der cert, return 0 on success */ @@ -6918,6 +7870,70 @@ int wc_EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key, return ret; } +int wc_EccPublicKeyDecode(const byte* input, word32* inOutIdx, + ecc_key* key, word32 inSz) +{ + int length; + int ret = 0; + + if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) + return BAD_FUNC_ARG; + + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + +#if defined(OPENSSL_EXTRA) + { + byte b = input[*inOutIdx]; + if (b != ASN_INTEGER) { + /* not from decoded cert, will have algo id, skip past */ + if (GetSequence(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + b = input[(*inOutIdx)++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + *inOutIdx += length; /* skip past */ + + /* ecc params information */ + b = input[(*inOutIdx)++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length, inSz) < 0) + return ASN_PARSE_E; + + *inOutIdx += length; /* skip past */ + + /* key header */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ASN_BIT_STRING) + ret = ASN_BITSTR_E; + else if (GetLength(input, inOutIdx, &length, inSz) < 0) + ret = ASN_PARSE_E; + else { + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != 0x00) + ret = ASN_EXPECT_0_E; + } + } + } /* openssl var block */ +#endif /* OPENSSL_EXTRA */ + + if (wc_ecc_import_x963(input+*inOutIdx, inSz - *inOutIdx, key) != 0) + return ASN_ECC_KEY_E; + + return ret; +} + #ifdef WOLFSSL_KEY_GEN diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ec4ef607e..454935498 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -208,7 +208,9 @@ int pbkdf2_test(void); int pkcs7enveloped_test(void); int pkcs7signed_test(void); #endif - +#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) +int certext_test(void); +#endif /* General big buffer size for many tests. */ #define FOURK_BUF 4096 @@ -267,6 +269,17 @@ int wolfcrypt_test(void* args) #endif /* USE_FAST_MATH */ #endif /* !NO_BIG_INT */ + if ( (ret = rsa_test()) != 0) + return err_sys("RSA EXT test failed!\n", ret); + else + printf( "RSA EXT test passed!\n"); + +#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) + if ( (ret = certext_test()) != 0) + return err_sys("CERT EXT test failed!\n", ret); + else + printf( "CERT EXT test passed!\n"); +#endif #ifndef NO_MD5 if ( (ret = md5_test()) != 0) @@ -3300,17 +3313,27 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #endif /* HAVE_NTRU */ + #ifndef NO_RSA #if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) #ifdef FREESCALE_MQX static const char* clientKey = "a:\\certs\\client-key.der"; static const char* clientCert = "a:\\certs\\client-cert.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* clientKeyPub = "a:\\certs\\client-keyPub.der"; + #endif #ifdef WOLFSSL_CERT_GEN static const char* caKeyFile = "a:\\certs\\ca-key.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* caKeyPubFile = "a:\\certs\\ca-keyPub.der"; + #endif static const char* caCertFile = "a:\\certs\\ca-cert.pem"; #ifdef HAVE_ECC static const char* eccCaKeyFile = "a:\\certs\\ecc-key.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* eccCaKeyPubFile = "a:\\certs\\ecc-keyPub.der"; + #endif static const char* eccCaCertFile = "a:\\certs\\server-ecc.pem"; #endif #endif @@ -3319,13 +3342,25 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) static char* clientCert = "certs/client-cert.der"; void set_clientKey(char *key) { clientKey = key ; } void set_clientCert(char *cert) { clientCert = cert ; } + #ifdef WOLFSSL_CERT_EXT + static const char* clientKeyPub = "certs/client-keyPub.der"; + void set_clientKeyPub(char *key) { clientKeyPub = key ; } + #endif #ifdef WOLFSSL_CERT_GEN static char* caKeyFile = "certs/ca-key.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* caKeyPubFile = "certs/ca-keyPub.der"; + void set_caKeyPubFile (char * key) { caKeyPubFile = key ; } + #endif static char* caCertFile = "certs/ca-cert.pem"; void set_caKeyFile (char * key) { caKeyFile = key ; } void set_caCertFile(char * cert) { caCertFile = cert ; } #ifdef HAVE_ECC static const char* eccCaKeyFile = "certs/ecc-key.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* eccCaKeyPubFile = "certs/ecc-keyPub.der"; + void set_eccCaKeyPubFile(char * key) { eccCaKeyPubFile = key ; } + #endif static const char* eccCaCertFile = "certs/server-ecc.pem"; void set_eccCaKeyFile (char * key) { eccCaKeyFile = key ; } void set_eccCaCertFile(char * cert) { eccCaCertFile = cert ; } @@ -3334,11 +3369,17 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #else static const char* clientKey = "./certs/client-key.der"; static const char* clientCert = "./certs/client-cert.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* clientKeyPub = "./certs/client-keyPub.der"; + #endif #ifdef WOLFSSL_CERT_GEN static const char* caKeyFile = "./certs/ca-key.der"; static const char* caCertFile = "./certs/ca-cert.pem"; #ifdef HAVE_ECC static const char* eccCaKeyFile = "./certs/ecc-key.der"; + #ifdef WOLFSSL_CERT_EXT + static const char* eccCaKeyPubFile = "./certs/ecc-keyPub.der"; + #endif static const char* eccCaCertFile = "./certs/server-ecc.pem"; #endif #endif @@ -3346,11 +3387,200 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #endif +#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) +int certext_test(void) +{ + DecodedCert cert; + byte* tmp; + size_t bytes; + FILE *file; + int ret; + + /* created from rsa_test : othercert.der */ + byte skid_rsa[] = "\x33\xD8\x45\x66\xD7\x68\x87\x18\x7E\x54" + "\x0D\x70\x27\x91\xC7\x26\xD7\x85\x65\xC0"; + + /* created from rsa_test : othercert.der */ + byte akid_rsa[] = "\x27\x8E\x67\x11\x74\xC3\x26\x1D\x3F\xED" + "\x33\x63\xB3\xA4\xD8\x1D\x30\xE5\xE8\xD5"; + + /* created from rsa_test : certecc.der */ + byte akid_ecc[] = "\x5D\x5D\x26\xEF\xAC\x7E\x36\xF9\x9B\x76" + "\x15\x2B\x4A\x25\x02\x23\xEF\xB2\x89\x30"; + + /* created from rsa_test : cert.der */ + byte kid_ca[] = "\x33\xD8\x45\x66\xD7\x68\x87\x18\x7E\x54" + "\x0D\x70\x27\x91\xC7\x26\xD7\x85\x65\xC0"; + + tmp = (byte*)malloc(FOURK_BUF); + if (tmp == NULL) + return -200; + + /* load othercert.pem (Cert signed by an authority) */ +#ifdef FREESCALE_MQX + file = fopen("a:\\certs\\othercert.der", "rb"); +#else + file = fopen("./othercert.der", "rb"); +#endif + if (!file) { + free(tmp); + return -200; + } + + bytes = fread(tmp, 1, FOURK_BUF, file); + fclose(file); + + InitDecodedCert(&cert, tmp, (word32)bytes, 0); + + ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, 0); + printf("ret = %d\n", ret); + if (ret != 0) + return -201; + + /* check the SKID from a RSA certificate */ + if (XMEMCMP(skid_rsa, cert.extSubjKeyId, cert.extSubjKeyIdSz)) + return -202; + + /* check the AKID from an RSA certificate */ + if (XMEMCMP(akid_rsa, cert.extAuthKeyId, cert.extAuthKeyIdSz)) + return -203; + + /* check the Key Usage from an RSA certificate */ + if (!cert.extKeyUsageSet) + return -204; + + if (cert.extKeyUsage != (KEYUSE_KEY_ENCIPHER|KEYUSE_KEY_AGREE)) + return -205; + + /* check the CA Basic Constraints from an RSA certificate */ + if (cert.isCA) + return -206; + + /* check the Certificate Policies Id */ + if (cert.extCertPoliciesNb != 1) + return -227; + + if (strncmp(cert.extCertPolicies[0], "2.16.840.1.101.3.4.1.42", 23)) + return -228; + + FreeDecodedCert(&cert); + + + /* load certecc.pem (Cert signed by an authority) */ +#ifdef FREESCALE_MQX + file = fopen("a:\\certs\\certecc.der", "rb"); +#else + file = fopen("./certecc.der", "rb"); +#endif + if (!file) { + free(tmp); + return -210; + } + + bytes = fread(tmp, 1, FOURK_BUF, file); + fclose(file); + + InitDecodedCert(&cert, tmp, (word32)bytes, 0); + + ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) + return -211; + + /* check the SKID from a ECC certificate */ + if (XMEMCMP(skid_rsa, cert.extSubjKeyId, cert.extSubjKeyIdSz)) + return -212; + + /* check the AKID from an ECC certificate */ + if (XMEMCMP(akid_ecc, cert.extAuthKeyId, cert.extAuthKeyIdSz)) + return -213; + + /* check the Key Usage from an ECC certificate */ + if (!cert.extKeyUsageSet) + return -214; + + if (cert.extKeyUsage != (KEYUSE_DIGITAL_SIG|KEYUSE_CONTENT_COMMIT)) + return -215; + + /* check the CA Basic Constraints from an ECC certificate */ + if (cert.isCA) + return -216; + + /* check the Certificate Policies Id */ + if (cert.extCertPoliciesNb != 2) + return -217; + + if (strncmp(cert.extCertPolicies[0], "2.4.589440.587.101.2.1.9632587.1", 32)) + return -218; + + if (strncmp(cert.extCertPolicies[1], "1.2.13025.489.1.113549", 22)) + return -219; + + FreeDecodedCert(&cert); + + /* load cert.pem (self signed certificate) */ +#ifdef FREESCALE_MQX + file = fopen("a:\\certs\\cert.der", "rb"); +#else + file = fopen("./cert.der", "rb"); +#endif + if (!file) { + free(tmp); + return -220; + } + + bytes = fread(tmp, 1, FOURK_BUF, file); + fclose(file); + + InitDecodedCert(&cert, tmp, (word32)bytes, 0); + + ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) + return -221; + + /* check the SKID from a CA certificate */ + if (XMEMCMP(kid_ca, cert.extSubjKeyId, cert.extSubjKeyIdSz)) + return -222; + + /* check the AKID from an CA certificate */ + if (XMEMCMP(kid_ca, cert.extAuthKeyId, cert.extAuthKeyIdSz)) + return -223; + + /* check the Key Usage from CA certificate */ + if (!cert.extKeyUsageSet) + return -224; + + if (cert.extKeyUsage != (KEYUSE_KEY_CERT_SIGN|KEYUSE_CRL_SIGN)) + return -225; + + /* check the CA Basic Constraints CA certificate */ + if (!cert.isCA) + return -226; + + /* check the Certificate Policies Id */ + if (cert.extCertPoliciesNb != 2) + return -227; + + if (strncmp(cert.extCertPolicies[0], "2.16.840.1.101.3.4.1.42", 23)) + return -228; + + if (strncmp(cert.extCertPolicies[1], "1.2.840.113549.1.9.16.6.5", 25)) + return -229; + + FreeDecodedCert(&cert); + + return 0; +} +#endif /* defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) */ + + int rsa_test(void) { byte* tmp; size_t bytes; RsaKey key; +#ifdef WOLFSSL_CERT_EXT + RsaKey keypub; +#endif WC_RNG rng; word32 idx = 0; int ret; @@ -3359,7 +3589,7 @@ int rsa_test(void) byte out[256]; byte plain[256]; #if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) - FILE* file, * file2; + FILE *file, *file2; #endif #ifdef WOLFSSL_TEST_CERT DecodedCert cert; @@ -3473,6 +3703,42 @@ int rsa_test(void) (void)bytes; #endif +#ifdef WOLFSSL_CERT_EXT + +#ifdef USE_CERT_BUFFERS_1024 + XMEMCPY(tmp, client_keypub_der_1024, sizeof_client_keypub_der_1024); + bytes = sizeof_client_keypub_der_1024; +#elif defined(USE_CERT_BUFFERS_2048) + XMEMCPY(tmp, client_keypub_der_2048, sizeof_client_keypub_der_2048); + bytes = sizeof_client_keypub_der_2048; +#else + file = fopen(clientKeyPub, "rb"); + if (!file) { + err_sys("can't open ./certs/client-keyPub.der, " + "Please run from wolfSSL home dir", -40); + free(tmp); + return -50; + } + + bytes = fread(tmp, 1, FOURK_BUF, file); + fclose(file); +#endif /* USE_CERT_BUFFERS */ + + ret = wc_InitRsaKey(&keypub, 0); + if (ret != 0) { + free(tmp); + return -51; + } + idx = 0; + + ret = wc_RsaPublicKeyDecode(tmp, &idx, &keypub, (word32)bytes); + if (ret != 0) { + free(tmp); + wc_FreeRsaKey(&keypub); + return -52; + } +#endif /* WOLFSSL_CERT_EXT */ + #ifdef WOLFSSL_KEY_GEN { byte* der; @@ -3634,6 +3900,39 @@ int rsa_test(void) myCert.isCA = 1; myCert.sigType = CTC_SHA256wRSA; +#ifdef WOLFSSL_CERT_EXT + /* add Policies */ + strncpy(myCert.certPolicies[0], "2.16.840.1.101.3.4.1.42", + CTC_MAX_CERTPOL_SZ); + strncpy(myCert.certPolicies[1], "1.2.840.113549.1.9.16.6.5", + CTC_MAX_CERTPOL_SZ); + myCert.certPoliciesNb = 2; + + /* add SKID from the Public Key */ + if (wc_SetSubjectKeyIdFromPublicKey(&myCert, &keypub, NULL) != 0) { + free(pem); + free(derCert); + free(tmp); + return -399; + } + + /* add AKID from the Public Key */ + if (wc_SetAuthKeyIdFromPublicKey(&myCert, &keypub, NULL) != 0) { + free(pem); + free(derCert); + free(tmp); + return -399; + } + + /* add Key Usage */ + if (wc_SetKeyUsage(&myCert,"cRLSign,keyCertSign") != 0) { + free(pem); + free(derCert); + free(tmp); + return -400; + } +#endif /* WOLFSSL_CERT_EXT */ + certSz = wc_MakeSelfCert(&myCert, derCert, FOURK_BUF, &key, &rng); if (certSz < 0) { free(derCert); @@ -3775,6 +4074,37 @@ int rsa_test(void) strncpy(myCert.subject.commonName, "www.yassl.com", CTC_NAME_SIZE); strncpy(myCert.subject.email, "info@yassl.com", CTC_NAME_SIZE); +#ifdef WOLFSSL_CERT_EXT + /* add Policies */ + strncpy(myCert.certPolicies[0], "2.16.840.1.101.3.4.1.42", + CTC_MAX_CERTPOL_SZ); + myCert.certPoliciesNb =1; + + /* add SKID from the Public Key */ + if (wc_SetSubjectKeyIdFromPublicKey(&myCert, &key, NULL) != 0) { + free(pem); + free(derCert); + free(tmp); + return -399; + } + + /* add AKID from the CA certificate */ + if (wc_SetAuthKeyId(&myCert, caCertFile) != 0) { + free(pem); + free(derCert); + free(tmp); + return -399; + } + + /* add Key Usage */ + if (wc_SetKeyUsage(&myCert,"keyEncipherment,keyAgreement") != 0) { + free(pem); + free(derCert); + free(tmp); + return -400; + } +#endif /* WOLFSSL_CERT_EXT */ + ret = wc_SetIssuer(&myCert, caCertFile); if (ret < 0) { free(derCert); @@ -3803,7 +4133,6 @@ int rsa_test(void) return -408; } - #ifdef WOLFSSL_TEST_CERT InitDecodedCert(&decode, derCert, certSz, 0); ret = ParseCert(&decode, CERT_TYPE, NO_VERIFY, 0); @@ -3887,6 +4216,9 @@ int rsa_test(void) size_t bytes3; word32 idx3 = 0; FILE* file3; +#ifdef WOLFSSL_CERT_EXT + ecc_key caKeyPub; +#endif #ifdef WOLFSSL_TEST_CERT DecodedCert decode; #endif @@ -3935,6 +4267,72 @@ int rsa_test(void) strncpy(myCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE); strncpy(myCert.subject.email, "info@wolfssl.com", CTC_NAME_SIZE); +#ifdef WOLFSSL_CERT_EXT + /* add Policies */ + strncpy(myCert.certPolicies[0], "2.4.589440.587.101.2.1.9632587.1", + CTC_MAX_CERTPOL_SZ); + strncpy(myCert.certPolicies[1], "1.2.13025.489.1.113549", + CTC_MAX_CERTPOL_SZ); + myCert.certPoliciesNb = 2; + + + file3 = fopen(eccCaKeyPubFile, "rb"); + if (!file3) { + free(derCert); + free(pem); + free(tmp); + return -5500; + } + + bytes3 = fread(tmp, 1, FOURK_BUF, file3); + fclose(file3); + + wc_ecc_init(&caKeyPub); + if (ret != 0) { + free(derCert); + free(pem); + free(tmp); + return -5501; + } + + idx3 = 0; + ret = wc_EccPublicKeyDecode(tmp, &idx3, &caKeyPub, (word32)bytes3); + if (ret != 0) { + free(derCert); + free(pem); + free(tmp); + wc_ecc_free(&caKeyPub); + return -5502; + } + + /* add SKID from the Public Key */ + if (wc_SetSubjectKeyIdFromPublicKey(&myCert, &key, NULL) != 0) { + free(pem); + free(derCert); + free(tmp); + wc_ecc_free(&caKeyPub); + return -5503; + } + + /* add AKID from the Public Key */ + if (wc_SetAuthKeyIdFromPublicKey(&myCert, NULL, &caKeyPub) != 0) { + free(pem); + free(derCert); + free(tmp); + wc_ecc_free(&caKeyPub); + return -5504; + } + wc_ecc_free(&caKeyPub); + + /* add Key Usage */ + if (wc_SetKeyUsage(&myCert,"digitalSignature,nonRepudiation") != 0) { + free(pem); + free(derCert); + free(tmp); + return -5505; + } +#endif /* WOLFSSL_CERT_EXT */ + ret = wc_SetIssuer(&myCert, eccCaCertFile); if (ret < 0) { free(pem); @@ -3944,7 +4342,7 @@ int rsa_test(void) return -5405; } - certSz = wc_MakeCert(&myCert, derCert, FOURK_BUF, NULL, &caKey, &rng); + certSz = wc_MakeCert(&myCert, derCert, FOURK_BUF, &key, NULL, &rng); if (certSz < 0) { free(pem); free(derCert); @@ -4045,7 +4443,7 @@ int rsa_test(void) FILE* ntruPrivFile; int certSz; int pemSz; - word32 idx3; + word32 idx3 = 0; #ifdef WOLFSSL_TEST_CERT DecodedCert decode; #endif @@ -4144,6 +4542,35 @@ int rsa_test(void) strncpy(myCert.subject.commonName, "www.yassl.com", CTC_NAME_SIZE); strncpy(myCert.subject.email, "info@yassl.com", CTC_NAME_SIZE); +#ifdef WOLFSSL_CERT_EXT + + /* add SKID from the Public Key */ + if (wc_SetSubjectKeyIdFromNtruPublicKey(&myCert, public_key, + public_key_len) != 0) { + free(pem); + free(derCert); + free(tmp); + return -496; + } + + /* add AKID from the CA certificate */ + if (wc_SetAuthKeyId(&myCert, caCertFile) != 0) { + free(pem); + free(derCert); + free(tmp); + return -495; + } + + /* add Key Usage */ + if (wc_SetKeyUsage(&myCert,"digitalSignature,nonRepudiation," + "keyEncipherment,keyAgreement") != 0) { + free(pem); + free(derCert); + free(tmp); + return -494; + } +#endif /* WOLFSSL_CERT_EXT */ + ret = wc_SetIssuer(&myCert, caCertFile); if (ret < 0) { free(derCert); @@ -4279,6 +4706,25 @@ int rsa_test(void) strncpy(req.subject.email, "info@yassl.com", CTC_NAME_SIZE); req.sigType = CTC_SHA256wRSA; +#ifdef WOLFSSL_CERT_EXT + /* add SKID from the Public Key */ + if (wc_SetSubjectKeyIdFromPublicKey(&req, &keypub, NULL) != 0) { + free(pem); + free(der); + free(tmp); + return -496; + } + + /* add Key Usage */ + if (wc_SetKeyUsage(&req,"digitalSignature,nonRepudiation," + "keyEncipherment,keyAgreement") != 0) { + free(pem); + free(der); + free(tmp); + return -494; + } +#endif /* WOLFSSL_CERT_EXT */ + derSz = wc_MakeCertReq(&req, der, FOURK_BUF, &key, NULL); if (derSz < 0) { free(pem); @@ -4352,6 +4798,9 @@ int rsa_test(void) #endif /* WOLFSSL_CERT_GEN */ wc_FreeRsaKey(&key); +#ifdef WOLFSSL_CERT_EXT + wc_FreeRsaKey(&keypub); +#endif #ifdef HAVE_CAVIUM wc_RsaFreeCavium(&key); #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index f1c492afa..58fe5dc00 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1069,11 +1069,16 @@ WOLFSSL_API int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version); WOLFSSL_API int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version); WOLFSSL_API int wolfSSL_GetObjectSize(void); /* object size based on build */ WOLFSSL_API int wolfSSL_SetVersion(WOLFSSL* ssl, int version); -WOLFSSL_API int wolfSSL_KeyPemToDer(const unsigned char*, int sz, unsigned char*, - int, const char*); -WOLFSSL_API int wolfSSL_CertPemToDer(const unsigned char*, int sz, unsigned char*, - int, int); - +WOLFSSL_API int wolfSSL_KeyPemToDer(const unsigned char*, int, + unsigned char*, int, const char*); +WOLFSSL_API int wolfSSL_CertPemToDer(const unsigned char*, int, + unsigned char*, int, int); +#ifdef WOLFSSL_CERT_EXT +WOLFSSL_API int wolfSSL_PemPubKeyToDer(const char* fileName, + unsigned char* derBuf, int derSz); +WOLFSSL_API int wolfSSL_PubKeyPemToDer(const unsigned char*, int, + unsigned char*, int); +#endif /* WOLFSSL_CERT_EXT */ typedef void (*CallbackCACache)(unsigned char* der, int sz, int type); typedef void (*CbMissingCRL)(const char* url); typedef int (*CbOCSPIO)(void*, const char*, int, diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 311cad852..b39114fa4 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -172,12 +172,20 @@ enum Misc_ASN { MAX_ATTRIB_SZ = MAX_SEQ_SZ * 3 + (11 + MAX_SEQ_SZ) * 2 + MAX_PRSTR_SZ + CTC_NAME_SIZE, /* 11 is the OID size */ #endif - #ifdef WOLFSSL_ALT_NAMES + #if defined(WOLFSSL_ALT_NAMES) || defined(WOLFSSL_CERT_EXT) MAX_EXTENSIONS_SZ = 1 + MAX_LENGTH_SZ + CTC_MAX_ALT_SIZE, #else MAX_EXTENSIONS_SZ = 1 + MAX_LENGTH_SZ + MAX_CA_SZ, #endif /* Max total extensions, id + len + others */ +#endif +#ifdef WOLFSSL_CERT_EXT + MAX_KID_SZ = 45, /* Max encoded KID length (SHA-256 case) */ + MAX_KEYUSAGE_SZ = 18, /* Max encoded Key Usage length */ + MAX_OID_SZ = 32, /* Max DER length of OID*/ + MAX_OID_STRING_SZ = 64, /* Max string length representation of OID*/ + MAX_CERTPOL_NB = CTC_MAX_CERTPOL_NB,/* Max number of Cert Policy */ + MAX_CERTPOL_SZ = CTC_MAX_CERTPOL_SZ, #endif MAX_OCSP_EXT_SZ = 58, /* Max OCSP Extension length */ MAX_OCSP_NONCE_SZ = 18, /* OCSP Nonce size */ @@ -277,17 +285,23 @@ enum VerifyType { VERIFY = 1 }; +#ifdef WOLFSSL_CERT_EXT +enum KeyIdType { + SKID_TYPE = 0, + AKID_TYPE = 1 +}; +#endif /* Key usage extension bits */ -#define KEYUSE_DIGITAL_SIG 0x0100 -#define KEYUSE_CONTENT_COMMIT 0x0080 -#define KEYUSE_KEY_ENCIPHER 0x0040 -#define KEYUSE_DATA_ENCIPHER 0x0020 -#define KEYUSE_KEY_AGREE 0x0010 -#define KEYUSE_KEY_CERT_SIGN 0x0008 -#define KEYUSE_CRL_SIGN 0x0004 -#define KEYUSE_ENCIPHER_ONLY 0x0002 -#define KEYUSE_DECIPHER_ONLY 0x0001 +#define KEYUSE_DIGITAL_SIG 0x0080 +#define KEYUSE_CONTENT_COMMIT 0x0040 +#define KEYUSE_KEY_ENCIPHER 0x0020 +#define KEYUSE_DATA_ENCIPHER 0x0010 +#define KEYUSE_KEY_AGREE 0x0008 +#define KEYUSE_KEY_CERT_SIGN 0x0004 +#define KEYUSE_CRL_SIGN 0x0002 +#define KEYUSE_ENCIPHER_ONLY 0x0001 +#define KEYUSE_DECIPHER_ONLY 0x8000 #define EXTKEYUSE_ANY 0x08 #define EXTKEYUSE_OCSP_SIGN 0x04 @@ -475,6 +489,10 @@ struct DecodedCert { byte extCertPolicyCrit; #endif /* OPENSSL_EXTRA */ #endif /* WOLFSSL_SEP */ +#ifdef WOLFSSL_CERT_EXT + char extCertPolicies[MAX_CERTPOL_NB][MAX_CERTPOL_SZ]; + int extCertPoliciesNb; +#endif /* WOLFSSL_CERT_EXT */ }; extern const char* BEGIN_CERT; @@ -495,6 +513,8 @@ extern const char* BEGIN_EC_PRIV; extern const char* END_EC_PRIV; extern const char* BEGIN_DSA_PRIV; extern const char* END_DSA_PRIV; +extern const char* BEGIN_PUB_KEY; +extern const char* END_PUB_KEY; #ifdef NO_SHA #define SIGNER_DIGEST_SIZE SHA256_DIGEST_SIZE diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 7aea6f927..2658a6518 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -47,7 +47,10 @@ enum CertType { CERTREQ_TYPE, DSA_TYPE, ECC_TYPE, - RSA_TYPE + RSA_TYPE, + PUBLICKEY_TYPE, + RSA_PUBLICKEY_TYPE, + ECC_PUBLICKEY_TYPE }; @@ -79,10 +82,18 @@ enum Ctc_Encoding { #endif enum Ctc_Misc { - CTC_NAME_SIZE = 64, - CTC_DATE_SIZE = 32, - CTC_MAX_ALT_SIZE = 16384, /* may be huge */ - CTC_SERIAL_SIZE = 8 + CTC_NAME_SIZE = 64, + CTC_DATE_SIZE = 32, + CTC_MAX_ALT_SIZE = 16384, /* may be huge */ + CTC_SERIAL_SIZE = 8, +#ifdef WOLFSSL_CERT_EXT + /* AKID could contains: hash + (Option) AuthCertIssuer,AuthCertSerialNum + * We support only hash */ + CTC_MAX_SKID_SIZE = SHA256_DIGEST_SIZE, + CTC_MAX_AKID_SIZE = SHA256_DIGEST_SIZE, + CTC_MAX_CERTPOL_SZ = 64, + CTC_MAX_CERTPOL_NB = 2 /* Max number of Certificate Policy */ +#endif /* WOLFSSL_CERT_EXT */ }; typedef struct CertName { @@ -125,6 +136,15 @@ typedef struct Cert { byte afterDate[CTC_DATE_SIZE]; /* after date copy */ int afterDateSz; /* size of copy */ #endif +#ifdef WOLFSSL_CERT_EXT + byte skid[CTC_MAX_SKID_SIZE]; /* Subject Key Identifier */ + int skidSz; /* SKID size in bytes */ + byte akid[CTC_MAX_AKID_SIZE]; /* Authority Key Identifier */ + int akidSz; /* AKID size in bytes */ + word16 keyUsage; /* Key Usage */ + char certPolicies[CTC_MAX_CERTPOL_NB][CTC_MAX_CERTPOL_SZ]; + word16 certPoliciesNb; /* Number of Cert Policy */ +#endif #ifdef WOLFSSL_CERT_REQ char challengePw[CTC_NAME_SIZE]; #endif @@ -168,6 +188,43 @@ WOLFSSL_API int wc_SetSubjectBuffer(Cert*, const byte*, int); WOLFSSL_API int wc_SetAltNamesBuffer(Cert*, const byte*, int); WOLFSSL_API int wc_SetDatesBuffer(Cert*, const byte*, int); +#ifdef WOLFSSL_CERT_EXT +WOLFSSL_API int wc_SetAuthKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, + ecc_key *eckey); +WOLFSSL_API int wc_SetAuthKeyIdFromCert(Cert *cert, const byte *der, int derSz); +WOLFSSL_API int wc_SetAuthKeyId(Cert *cert, const char* file); +WOLFSSL_API int wc_SetSubjectKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, + ecc_key *eckey); +WOLFSSL_API int wc_SetSubjectKeyId(Cert *cert, const char* file); + +#ifdef HAVE_NTRU +WOLFSSL_API int wc_SetSubjectKeyIdFromNtruPublicKey(Cert *cert, byte *ntruKey, + word16 ntruKeySz); +#endif + +/* Set the KeyUsage. + * Value is a string separated tokens with ','. Accepted tokens are : + * digitalSignature,nonRepudiation,contentCommitment,keyCertSign,cRLSign, + * dataEncipherment,keyAgreement,keyEncipherment,encipherOnly and decipherOnly. + * + * nonRepudiation and contentCommitment are for the same usage. + */ +WOLFSSL_API int wc_SetKeyUsage(Cert *cert, const char *value); + +/* encode Certificate Policies, return total bytes written + * each input value must be ITU-T X.690 formatted : a.b.c... + * input must be an array of values with a NULL terminated for the latest + * RFC5280 : non-critical */ +WOLFSSL_API int wc_SetCertificatePolicies(Cert *cert, const char **input); + +/* forward from wolfssl */ +WOLFSSL_API int wolfSSL_PemPubKeyToDer(const char* fileName, + unsigned char* derBuf, int derSz); +/* forward from wolfssl */ +WOLFSSL_API int wolfSSL_PubKeyPemToDer(const unsigned char*, int, + unsigned char*, int); +#endif /* WOLFSSL_CERT_EXT */ + #ifdef HAVE_NTRU WOLFSSL_API int wc_MakeNtruCert(Cert*, byte* derBuffer, word32 derSz, const byte* ntruKey, word16 keySz, @@ -186,9 +243,13 @@ WOLFSSL_API int wc_SetDatesBuffer(Cert*, const byte*, int); #ifdef HAVE_ECC /* private key helpers */ - WOLFSSL_API int wc_EccPrivateKeyDecode(const byte* input,word32* inOutIdx, - ecc_key*,word32); + WOLFSSL_API int wc_EccPrivateKeyDecode(const byte*, word32*, + ecc_key*, word32); WOLFSSL_API int wc_EccKeyToDer(ecc_key*, byte* output, word32 inLen); + + /* public key helper */ + WOLFSSL_API int wc_EccPublicKeyDecode(const byte*, word32*, + ecc_key*, word32); #endif /* DER encode signature */ diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 340d1db75..4e39d77cd 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -155,6 +155,14 @@ enum { SRP_VERIFY_E = -218, /* SRP proof verification failed. */ SRP_BAD_KEY_E = -219, /* SRP bad ephemeral values. */ + ASN_NO_SKID = -220, /* ASN no Subject Key Identifier found */ + ASN_NO_AKID = -221, /* ASN no Authority Key Identifier found */ + ASN_NO_KEYUSAGE = -223, /* ASN no Key Usage found */ + SKID_E = -224, /* setting Subject Key Identifier error */ + AKID_E = -225, /* setting Authority Key Identifier error */ + KEYUSAGE_E = -226, /* Bad Key Usage value */ + CERTPOLICIES_E = -227, /* setting Certificate Policies error */ + MIN_CODE_E = -300 /* errors -101 - -299 */ }; diff --git a/wolfssl/wolfcrypt/logging.h b/wolfssl/wolfcrypt/logging.h index 2e604080d..ad519f76d 100644 --- a/wolfssl/wolfcrypt/logging.h +++ b/wolfssl/wolfcrypt/logging.h @@ -25,6 +25,10 @@ #ifndef WOLFSSL_LOGGING_H #define WOLFSSL_LOGGING_H +#ifdef DEBUG_WOLFSSL +#include +#endif + #include #ifdef __cplusplus diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 4a1dc31f8..a75dbd62e 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -190,6 +190,7 @@ #ifndef STRING_USER #include + #include /* for snprintf */ char* mystrnstr(const char* s1, const char* s2, unsigned int n); #define XMEMCPY(d,s,l) memcpy((d),(s),(l))