ASN1 Extended Key Usage support. Adds new `wc_SetExtKeyUsage()` API. Available only with `--enable-certext` or `WOLFSSL_CERT_EXT`.

pull/1160/head
David Garske 2017-09-26 12:05:46 -07:00
parent 8f3aa49ef6
commit 9eb7e2aafa
6 changed files with 260 additions and 21 deletions

View File

@ -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 */

View File

@ -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";

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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