diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3c4e5dcb1..24521897e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -1177,9 +1177,12 @@ static const byte extAltNamesHwNameOid[] = {43, 6, 1, 5, 5, 7, 8, 4}; /* certKeyUseType */ static const byte extExtKeyUsageAnyOid[] = {85, 29, 37, 0}; -static const byte extExtKeyUsageServerAuthOid[] = {43, 6, 1, 5, 5, 7, 3, 1}; -static const byte extExtKeyUsageClientAuthOid[] = {43, 6, 1, 5, 5, 7, 3, 2}; -static const byte extExtKeyUsageOcspSignOid[] = {43, 6, 1, 5, 5, 7, 3, 9}; +static const byte extExtKeyUsageServerAuthOid[] = {43, 6, 1, 5, 5, 7, 3, 1}; +static const byte extExtKeyUsageClientAuthOid[] = {43, 6, 1, 5, 5, 7, 3, 2}; +static const byte extExtKeyUsageCodeSigningOid[] = {43, 6, 1, 5, 5, 7, 3, 3}; +static const byte extExtKeyUsageEmailProtectOid[] = {43, 6, 1, 5, 5, 7, 3, 4}; +static const byte extExtKeyUsageTimestampOid[] = {43, 6, 1, 5, 5, 7, 3, 8}; +static const byte extExtKeyUsageOcspSignOid[] = {43, 6, 1, 5, 5, 7, 3, 9}; /* kdfType */ static const byte pbkdf2Oid[] = {42, 134, 72, 134, 247, 13, 1, 5, 12}; @@ -1475,6 +1478,18 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) oid = extExtKeyUsageClientAuthOid; *oidSz = sizeof(extExtKeyUsageClientAuthOid); break; + case EKU_CODESIGNING_OID: + oid = extExtKeyUsageCodeSigningOid; + *oidSz = sizeof(extExtKeyUsageCodeSigningOid); + break; + case EKU_EMAILPROTECT_OID: + oid = extExtKeyUsageEmailProtectOid; + *oidSz = sizeof(extExtKeyUsageEmailProtectOid); + break; + case EKU_TIMESTAMP_OID: + oid = extExtKeyUsageTimestampOid; + *oidSz = sizeof(extExtKeyUsageTimestampOid); + break; case EKU_OCSP_SIGN_OID: oid = extExtKeyUsageOcspSignOid; *oidSz = sizeof(extExtKeyUsageOcspSignOid); @@ -5473,6 +5488,15 @@ static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert) case EKU_CLIENT_AUTH_OID: cert->extExtKeyUsage |= EXTKEYUSE_CLIENT_AUTH; break; + case EKU_CODESIGNING_OID: + cert->extExtKeyUsage |= EXTKEYUSE_CODESIGN; + break; + case EKU_EMAILPROTECT_OID: + cert->extExtKeyUsage |= EXTKEYUSE_EMAILPROT; + break; + case EKU_TIMESTAMP_OID: + cert->extExtKeyUsage |= EXTKEYUSE_TIMESTAMP; + break; case EKU_OCSP_SIGN_OID: cert->extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN; break; @@ -6921,6 +6945,7 @@ int wc_InitCert(Cert* cert) cert->skidSz = 0; cert->akidSz = 0; cert->keyUsage = 0; + cert->extKeyUsage = 0; cert->certPoliciesNb = 0; XMEMSET(cert->akid, 0, CTC_MAX_AKID_SIZE); XMEMSET(cert->skid, 0, CTC_MAX_SKID_SIZE); @@ -6990,6 +7015,7 @@ typedef struct DerCert { 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 extKeyUsage[MAX_EXTKEYUSAGE_SZ]; /* Extended Key Usage extension */ byte certPolicies[MAX_CERTPOL_NB*MAX_CERTPOL_SZ]; /* Certificate Policies */ #endif #ifdef WOLFSSL_CERT_REQ @@ -7011,6 +7037,7 @@ typedef struct DerCert { int skidSz; /* encoded SKID extension length */ int akidSz; /* encoded SKID extension length */ int keyUsageSz; /* encoded KeyUsage extension length */ + int extKeyUsageSz; /* encoded ExtendedKeyUsage extension length */ int certPoliciesSz; /* encoded CertPolicies extension length*/ #endif #ifdef WOLFSSL_ALT_NAMES @@ -7727,7 +7754,6 @@ static int SetKeyUsage(byte* output, word32 outSz, word16 input) int idx; static const byte keyusage_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04}; - if (output == NULL) return BAD_FUNC_ARG; @@ -7736,6 +7762,85 @@ static int SetKeyUsage(byte* output, word32 outSz, word16 input) ku, idx); } +static int SetOjectIdValue(byte* output, word32 outSz, int* idx, + const byte* oid, word32 oidSz) +{ + /* verify room */ + if (*idx + 2 + oidSz >= outSz) + return ASN_PARSE_E; + + *idx += SetObjectId(oidSz, &output[*idx]); + XMEMCPY(&output[*idx], oid, oidSz); + *idx += oidSz; + + return 0; +} + +/* encode Extended Key Usage (RFC 5280 4.2.1.12), return total bytes written */ +static int SetExtKeyUsage(byte* output, word32 outSz, byte input) +{ + int idx = 0, oidListSz = 0, totalSz, ret = 0; + static const byte extkeyusage_oid[] = { 0x06, 0x03, 0x55, 0x1d, 0x25 }; + + if (output == NULL) + return BAD_FUNC_ARG; + + /* Skip to OID List */ + totalSz = 2 + sizeof(extkeyusage_oid) + 4; + idx = totalSz; + + /* Build OID List */ + /* If any set, then just use it */ + if (input & EXTKEYUSE_ANY) { + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageAnyOid, sizeof(extExtKeyUsageAnyOid)); + } + else { + if (input & EXTKEYUSE_SERVER_AUTH) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageServerAuthOid, sizeof(extExtKeyUsageServerAuthOid)); + if (input & EXTKEYUSE_CLIENT_AUTH) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageClientAuthOid, sizeof(extExtKeyUsageClientAuthOid)); + if (input & EXTKEYUSE_CODESIGN) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageCodeSigningOid, sizeof(extExtKeyUsageCodeSigningOid)); + if (input & EXTKEYUSE_EMAILPROT) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageEmailProtectOid, sizeof(extExtKeyUsageEmailProtectOid)); + if (input & EXTKEYUSE_TIMESTAMP) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageTimestampOid, sizeof(extExtKeyUsageTimestampOid)); + if (input & EXTKEYUSE_OCSP_SIGN) + ret |= SetOjectIdValue(output, outSz, &idx, + extExtKeyUsageOcspSignOid, sizeof(extExtKeyUsageOcspSignOid)); + } + if (ret != 0) + return ASN_PARSE_E; + + /* Calculate Sizes */ + oidListSz = idx - totalSz; + totalSz = idx - 2; /* exclude first seq/len (2) */ + + /* 1. Seq + Total Len (2) */ + idx = SetSequence(totalSz, output); + + /* 2. Object ID (2) */ + XMEMCPY(&output[idx], extkeyusage_oid, sizeof(extkeyusage_oid)); + idx += sizeof(extkeyusage_oid); + + /* 3. Octect String (2) */ + idx += SetOctetString(totalSz - idx, &output[idx]); + + /* 4. Seq + OidListLen (2) */ + idx += SetSequence(oidListSz, &output[idx]); + + /* 5. Oid List (already set in-place above) */ + idx += oidListSz; + + return idx; +} + /* Encode OID string representation to ITU-T X.690 format */ static int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) { @@ -8231,6 +8336,18 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, else der->keyUsageSz = 0; + /* Extended Key Usage */ + if (cert->extKeyUsage != 0){ + der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage, + sizeof(der->extKeyUsage), cert->extKeyUsage); + if (der->extKeyUsageSz <= 0) + return EXTKEYUSAGE_E; + + der->extensionsSz += der->extKeyUsageSz; + } + else + der->extKeyUsageSz = 0; + /* Certificate Policies */ if (cert->certPoliciesNb != 0) { der->certPoliciesSz = SetCertificatePolicies(der->certPolicies, @@ -8305,6 +8422,15 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, return EXTENSIONS_E; } + /* put ExtendedKeyUsage */ + if (der->extKeyUsageSz) { + ret = SetExtensions(der->extensions, sizeof(der->extensions), + &der->extensionsSz, + der->extKeyUsage, der->extKeyUsageSz); + if (ret <= 0) + return EXTENSIONS_E; + } + /* put Certificate Policies */ if (der->certPoliciesSz) { ret = SetExtensions(der->extensions, sizeof(der->extensions), @@ -8742,6 +8868,19 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, } else der->keyUsageSz = 0; + + /* Extended Key Usage */ + if (cert->extKeyUsage != 0){ + der->extKeyUsageSz = SetExtKeyUsage(der->extKeyUsage, + sizeof(der->extKeyUsage), cert->extKeyUsage); + if (der->extKeyUsageSz <= 0) + return EXTKEYUSAGE_E; + + der->extensionsSz += der->extKeyUsageSz; + } + else + der->extKeyUsageSz = 0; + #endif /* WOLFSSL_CERT_EXT */ /* put extensions */ @@ -8790,6 +8929,15 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, return EXTENSIONS_E; } + /* put ExtendedKeyUsage */ + if (der->extKeyUsageSz) { + ret = SetExtensions(der->extensions, sizeof(der->extensions), + &der->extensionsSz, + der->extKeyUsage, der->extKeyUsageSz); + if (ret <= 0) + return EXTENSIONS_E; + } + #endif /* WOLFSSL_CERT_EXT */ } @@ -9349,8 +9497,7 @@ int wc_SetKeyUsage(Cert *cert, const char *value) cert->keyUsage = 0; - str = (char *)XMALLOC(XSTRLEN(value)+1, cert->heap, - DYNAMIC_TYPE_TMP_BUFFER); + str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); if (str == NULL) return MEMORY_E; @@ -9396,6 +9543,61 @@ int wc_SetKeyUsage(Cert *cert, const char *value) XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } + +/* Set ExtendedKeyUsage from human readable string */ +int wc_SetExtKeyUsage(Cert *cert, const char *value) +{ + int ret = 0; + char *token, *str, *ptr; + word32 len; + + if (cert == NULL || value == NULL) + return BAD_FUNC_ARG; + + cert->extKeyUsage = 0; + + str = (char*)XMALLOC(XSTRLEN(value)+1, cert->heap, 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 */ + if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { + XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); + return EXTKEYUSAGE_E; + } + + while (token != NULL) + { + len = (word32)XSTRLEN(token); + + if (!XSTRNCASECMP(token, "any", len)) + cert->extKeyUsage |= EXTKEYUSE_ANY; + else if (!XSTRNCASECMP(token, "serverAuth", len)) + cert->extKeyUsage |= EXTKEYUSE_SERVER_AUTH; + else if (!XSTRNCASECMP(token, "clientAuth", len)) + cert->extKeyUsage |= EXTKEYUSE_CLIENT_AUTH; + else if (!XSTRNCASECMP(token, "codeSigning", len)) + cert->extKeyUsage |= EXTKEYUSE_CODESIGN; + else if (!XSTRNCASECMP(token, "emailProtection", len)) + cert->extKeyUsage |= EXTKEYUSE_EMAILPROT; + else if (!XSTRNCASECMP(token, "timeStamping", len)) + cert->extKeyUsage |= EXTKEYUSE_TIMESTAMP; + else if (!XSTRNCASECMP(token, "OCSPSigning", len)) + cert->extKeyUsage |= EXTKEYUSE_OCSP_SIGN; + else { + ret = EXTKEYUSAGE_E; + break; + } + + token = XSTRTOK(NULL, ",", &ptr); + } + + XFREE(str, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} #endif /* WOLFSSL_CERT_EXT */ diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 4d8f32a99..554de6812 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -369,7 +369,10 @@ const char* wc_GetErrorString(int error) return "Setting Authority Key Identifier error"; case KEYUSAGE_E: - return "Bad Key Usage value error"; + return "Key Usage value error"; + + case EXTKEYUSAGE_E: + return "Extended Key Usage value error"; case CERTPOLICIES_E: return "Setting Certificate Policies error"; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index d5c31e0cf..005c60010 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8921,13 +8921,30 @@ int rsa_test(void) "keyEncipherment,keyAgreement") != 0) { ERROR_OUT(-5683, exit_rsa); } + + /* add Extended Key Usage */ + if (wc_SetExtKeyUsage(&req, "serverAuth,clientAuth,codeSigning," + "emailProtection,timeStamping,OCSPSigning") != 0) { + ERROR_OUT(-5684, exit_rsa); + } #endif /* WOLFSSL_CERT_EXT */ derSz = wc_MakeCertReq(&req, der, FOURK_BUF, &key, NULL); if (derSz < 0) { - ERROR_OUT(-5684, exit_rsa); + ERROR_OUT(-5685, exit_rsa); } + #ifdef WOLFSSL_CERT_EXT + /* Try again with "any" flag set, will override all others */ + if (wc_SetExtKeyUsage(&req, "any") != 0) { + ERROR_OUT(-5686, exit_rsa); + } + derSz = wc_MakeCertReq(&req, der, FOURK_BUF, &key, NULL); + if (derSz < 0) { + ERROR_OUT(-5687, exit_rsa); + } + #endif /* WOLFSSL_CERT_EXT */ + ret = 0; do { #if defined(WOLFSSL_ASYNC_CRYPT) @@ -8939,35 +8956,35 @@ int rsa_test(void) } } while (ret == WC_PENDING_E); if (ret < 0) { - ERROR_OUT(-5685, exit_rsa); + ERROR_OUT(-5688, exit_rsa); } derSz = ret; pemSz = wc_DerToPem(der, derSz, pem, FOURK_BUF, CERTREQ_TYPE); if (pemSz < 0) { - ERROR_OUT(-5686, exit_rsa); + ERROR_OUT(-5689, exit_rsa); } #if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) reqFile = fopen(certReqDerFile, "wb"); if (!reqFile) { - ERROR_OUT(-5687, exit_rsa); + ERROR_OUT(-5690, exit_rsa); } ret = (int)fwrite(der, 1, derSz, reqFile); fclose(reqFile); if (ret != derSz) { - ERROR_OUT(-5688, exit_rsa); + ERROR_OUT(-5691, exit_rsa); } reqFile = fopen(certReqPemFile, "wb"); if (!reqFile) { - ERROR_OUT(-5689, exit_rsa); + ERROR_OUT(-5692, exit_rsa); } ret = (int)fwrite(pem, 1, pemSz, reqFile); fclose(reqFile); if (ret != pemSz) { - ERROR_OUT(-5690, exit_rsa); + ERROR_OUT(-5693, exit_rsa); } #endif diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 2ffa39d0b..401d5a08e 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -179,6 +179,8 @@ enum Misc_ASN { #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_EXTKEYUSAGE_SZ = 12 + (6 * (8 + 2)), /* Max encoded ExtKeyUsage + (SEQ/LEN + OBJID + OCTSTR/LEN + SEQ + (6 * (SEQ + OID))) */ 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 */ @@ -338,7 +340,10 @@ enum ExtKeyUsage_Sum { /* From RFC 5280 */ EKU_ANY_OID = 151, /* 2.5.29.37.0, anyExtendedKeyUsage */ EKU_SERVER_AUTH_OID = 71, /* 1.3.6.1.5.5.7.3.1, id-kp-serverAuth */ EKU_CLIENT_AUTH_OID = 72, /* 1.3.6.1.5.5.7.3.2, id-kp-clientAuth */ - EKU_OCSP_SIGN_OID = 79 /* 1.3.6.1.5.5.7.3.9, OCSPSigning */ + EKU_CODESIGNING_OID = 73, /* 1.3.6.1.5.5.7.3.3, id-kp-codeSigning */ + EKU_EMAILPROTECT_OID = 74, /* 1.3.6.1.5.5.7.3.4, id-kp-emailProtection */ + EKU_TIMESTAMP_OID = 78, /* 1.3.6.1.5.5.7.3.8, id-kp-timeStamping */ + EKU_OCSP_SIGN_OID = 79 /* 1.3.6.1.5.5.7.3.9, id-kp-OCSPSigning */ }; @@ -356,7 +361,7 @@ enum KeyIdType { }; #endif -/* Key usage extension bits */ +/* Key usage extension bits (based on RFC 5280) */ #define KEYUSE_DIGITAL_SIG 0x0080 #define KEYUSE_CONTENT_COMMIT 0x0040 #define KEYUSE_KEY_ENCIPHER 0x0020 @@ -367,10 +372,14 @@ enum KeyIdType { #define KEYUSE_ENCIPHER_ONLY 0x0001 #define KEYUSE_DECIPHER_ONLY 0x8000 -#define EXTKEYUSE_ANY 0x08 -#define EXTKEYUSE_OCSP_SIGN 0x04 -#define EXTKEYUSE_CLIENT_AUTH 0x02 -#define EXTKEYUSE_SERVER_AUTH 0x01 +/* Extended Key Usage bits (internal mapping only) */ +#define EXTKEYUSE_OCSP_SIGN 0x40 +#define EXTKEYUSE_TIMESTAMP 0x20 +#define EXTKEYUSE_EMAILPROT 0x10 +#define EXTKEYUSE_CODESIGN 0x08 +#define EXTKEYUSE_CLIENT_AUTH 0x04 +#define EXTKEYUSE_SERVER_AUTH 0x02 +#define EXTKEYUSE_ANY 0x01 typedef struct DNS_entry DNS_entry; diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 8f9a25b86..d9addfe97 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -159,6 +159,7 @@ typedef struct Cert { byte akid[CTC_MAX_AKID_SIZE]; /* Authority Key Identifier */ int akidSz; /* AKID size in bytes */ word16 keyUsage; /* Key Usage */ + byte extKeyUsage; /* Extended Key Usage */ char certPolicies[CTC_MAX_CERTPOL_NB][CTC_MAX_CERTPOL_SZ]; word16 certPoliciesNb; /* Number of Cert Policy */ #endif @@ -235,6 +236,12 @@ WOLFSSL_API int wc_SetSubjectKeyIdFromNtruPublicKey(Cert *cert, byte *ntruKey, */ WOLFSSL_API int wc_SetKeyUsage(Cert *cert, const char *value); +/* Set ExtendedKeyUsage + * Value is a string separated tokens with ','. Accepted tokens are : + * any,serverAuth,clientAuth,codeSigning,emailProtection,timeStamping,OCSPSigning + */ +WOLFSSL_API int wc_SetExtKeyUsage(Cert *cert, const char *value); + #endif /* WOLFSSL_CERT_EXT */ #ifdef HAVE_NTRU diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 1ff1ae935..0b75e126b 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -190,8 +190,9 @@ enum { ASYNC_OP_E = -245, /* Async operation error */ ECC_PRIVATEONLY_E = -246, /* Invalid use of private only ECC key*/ + EXTKEYUSAGE_E = -247, /* Bad Extended Key Usage value */ - WC_LAST_E = -246, /* Update this to indicate last error */ + WC_LAST_E = -247, /* Update this to indicate last error */ MIN_CODE_E = -300 /* errors -101 - -299 */ /* add new companion error id strings for any new error codes