From 0fd6aed9b6abf2dc018b44430d8752ad0548bedc Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 19 Nov 2013 14:44:55 -0800 Subject: [PATCH] Save more decoded data from certificate for later use with X.509 functions. --- ctaocrypt/src/asn.c | 118 +++++++++++++++++++++++-- cyassl/ctaocrypt/asn.h | 37 +++++++- cyassl/ctaocrypt/settings.h | 34 ++++++++ cyassl/internal.h | 25 ++++++ cyassl/ssl.h | 13 +++ src/internal.c | 52 +++++++++++ src/ssl.c | 167 ++++++++++++++++++++++++++++++++++++ 7 files changed, 439 insertions(+), 7 deletions(-) diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index cabd8d816..ff9b62c0d 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -1303,6 +1303,20 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) #ifdef OPENSSL_EXTRA XMEMSET(&cert->issuerName, 0, sizeof(DecodedName)); XMEMSET(&cert->subjectName, 0, sizeof(DecodedName)); + cert->extBasicConstSet = 0; + cert->extBasicConstCrit = 0; + cert->extBasicConstPlSet = 0; + cert->pathLength = 0; + cert->extSubjAltNameSet = 0; + cert->extSubjAltNameCrit = 0; + cert->extAuthKeyIdCrit = 0; + cert->extSubjKeyIdCrit = 0; + cert->extKeyUsageSet = 0; + cert->extKeyUsageCrit = 0; + cert->extKeyUsage = 0; + #ifdef HAVE_ECC + cert->pkCurveOID = 0; + #endif /* HAVE_ECC */ #endif /* OPENSSL_EXTRA */ #ifdef CYASSL_SEP cert->deviceTypeSz = 0; @@ -1311,6 +1325,10 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) cert->hwType = NULL; cert->hwSerialNumSz = 0; cert->hwSerialNum = NULL; + #ifdef OPENSSL_EXTRA + cert->extCertPolicySet = 0; + cert->extCertPolicyCrit = 0; + #endif /* OPENSSL_EXTRA */ #endif /* CYASSL_SEP */ } @@ -1509,6 +1527,9 @@ static int GetKey(DecodedCert* cert) oid += cert->source[cert->srcIdx++]; if (CheckCurve(oid) < 0) return ECC_CURVE_OID_E; + #ifdef OPENSSL_EXTRA + cert->pkCurveOID = oid; + #endif /* OPENSSL_EXTRA */ /* key header */ b = cert->source[cert->srcIdx++]; @@ -2882,8 +2903,28 @@ static void DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert) return; } - if (input[idx]) + if (input[idx++]) cert->isCA = 1; + + #ifdef OPENSSL_EXTRA + /* If there isn't any more data, return. */ + if (idx >= (word32)sz) + return; + + /* Anything left should be the optional pathlength */ + if (input[idx++] != ASN_INTEGER) { + CYASSL_MSG("\tfail: pathlen not INTEGER"); + return; + } + + if (input[idx++] != 1) { + CYASSL_MSG("\tfail: pathlen too long"); + return; + } + + cert->pathLength = input[idx]; + cert->extBasicConstPlSet = 1; + #endif /* OPENSSL_EXTRA */ } @@ -3045,7 +3086,6 @@ static void DecodeAuthKeyId(byte* input, int sz, DecodedCert* cert) ShaUpdate(&sha, input + idx, length); ShaFinal(&sha, cert->extAuthKeyId); } - cert->extAuthKeyIdSet = 1; return; } @@ -3077,12 +3117,44 @@ static void DecodeSubjKeyId(byte* input, int sz, DecodedCert* cert) ShaUpdate(&sha, input + idx, length); ShaFinal(&sha, cert->extSubjKeyId); } - cert->extSubjKeyIdSet = 1; return; } +#ifdef OPENSSL_EXTRA + static void DecodeKeyUsage(byte* input, int sz, DecodedCert* cert) + { + word32 idx = 0; + int length; + byte unusedBits; + CYASSL_ENTER("DecodeKeyUsage"); + + if (input[idx++] != ASN_BIT_STRING) { + CYASSL_MSG("\tfail: key usage expected bit string"); + return; + } + + if (GetLength(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tfail: key usage bad length"); + return; + } + + unusedBits = input[idx++]; + length--; + + if (length == 2) { + cert->extKeyUsage = (input[idx] << 8) | input[idx+1]; + cert->extKeyUsage >>= unusedBits; + } + else if (length == 1) + cert->extKeyUsage = (input[idx] << 1); + + return; + } +#endif /* OPENSSL_EXTRA */ + + #ifdef CYASSL_SEP static void DecodeCertPolicy(byte* input, int sz, DecodedCert* cert) { @@ -3138,6 +3210,7 @@ static void DecodeCertExtensions(DecodedCert* cert) byte* input = cert->extensions; int length; word32 oid; + byte critical; CYASSL_ENTER("DecodeCertExtensions"); @@ -3162,9 +3235,16 @@ static void DecodeCertExtensions(DecodedCert* cert) } /* check for critical flag */ + critical = 0; if (input[idx] == ASN_BOOLEAN) { - CYASSL_MSG("\tfound optional critical flag, moving past"); - idx += (ASN_BOOL_SIZE + 1); + int boolLength = 0; + idx++; + if (GetLength(input, &idx, &boolLength, sz) < 0) { + CYASSL_MSG("\tfail: critical boolean length"); + return; + } + if (input[idx++]) + critical = 1; } /* process the extension based on the OID */ @@ -3180,6 +3260,10 @@ static void DecodeCertExtensions(DecodedCert* cert) switch (oid) { case BASIC_CA_OID: + #ifdef OPENSSL_EXTRA + cert->extBasicConstSet = 1; + cert->extBasicConstCrit = critical; + #endif DecodeBasicCaConstraint(&input[idx], length, cert); break; @@ -3192,23 +3276,47 @@ static void DecodeCertExtensions(DecodedCert* cert) break; case ALT_NAMES_OID: + #ifdef OPENSSL_EXTRA + cert->extSubjAltNameSet = 1; + cert->extSubjAltNameCrit = critical; + #endif DecodeAltNames(&input[idx], length, cert); break; case AUTH_KEY_OID: + cert->extAuthKeyIdSet = 1; + #ifdef OPENSSL_EXTRA + cert->extAuthKeyIdCrit = critical; + #endif DecodeAuthKeyId(&input[idx], length, cert); break; case SUBJ_KEY_OID: + cert->extSubjKeyIdSet = 1; + #ifdef OPENSSL_EXTRA + cert->extSubjKeyIdCrit = critical; + #endif DecodeSubjKeyId(&input[idx], length, cert); break; #ifdef CYASSL_SEP case CERT_POLICY_OID: + #ifdef OPENSSL_EXTRA + cert->extCertPolicySet = 1; + cert->extCertPolicyCrit = critical; + #endif DecodeCertPolicy(&input[idx], length, cert); break; #endif + #ifdef OPENSSL_EXTRA + case KEY_USAGE_OID: + cert->extKeyUsageSet = 1; + cert->extKeyUsageCrit = critical; + DecodeKeyUsage(&input[idx], length, cert); + break; + #endif + default: CYASSL_MSG("\tExtension type not handled, skipping"); break; diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index ae758aab7..d4621c025 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -199,7 +199,8 @@ enum Extensions_Sum { CA_ISSUER_OID = 117, AUTH_KEY_OID = 149, SUBJ_KEY_OID = 128, - CERT_POLICY_OID = 146 + CERT_POLICY_OID = 146, + KEY_USAGE_OID = 129 /* 2.5.29.15 */ }; enum CertificatePolicy_Sum { @@ -217,6 +218,18 @@ enum VerifyType { }; +/* 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 + + typedef struct DNS_entry DNS_entry; struct DNS_entry { @@ -297,7 +310,23 @@ struct DecodedCert { byte extSubjKeyIdSet; /* Set when the SKID was read from cert */ byte extAuthKeyId[SHA_SIZE]; /* Authority Key ID */ byte extAuthKeyIdSet; /* Set when the AKID was read from cert */ - byte isCA; /* CA basic constraint true */ + byte isCA; /* CA basic constraint true */ +#ifdef OPENSSL_EXTRA + byte extBasicConstSet; + byte extBasicConstCrit; + byte extBasicConstPlSet; + word32 pathLength; /* CA basic constraint path length, opt */ + byte extSubjAltNameSet; + byte extSubjAltNameCrit; + byte extAuthKeyIdCrit; + byte extSubjKeyIdCrit; + byte extKeyUsageSet; + byte extKeyUsageCrit; + word16 extKeyUsage; /* Key usage bitfield */ + #ifdef HAVE_ECC + word32 pkCurveOID; /* Public Key's curve OID */ + #endif /* HAVE_ECC */ +#endif byte* beforeDate; int beforeDateLen; byte* afterDate; @@ -330,6 +359,10 @@ struct DecodedCert { byte* hwType; int hwSerialNumSz; byte* hwSerialNum; + #ifdef OPENSSL_EXTRA + byte extCertPolicySet; + byte extCertPolicyCrit; + #endif /* OPENSSL_EXTRA */ #endif /* CYASSL_SEP */ }; diff --git a/cyassl/ctaocrypt/settings.h b/cyassl/ctaocrypt/settings.h index d61c5484a..6f5a3d70a 100644 --- a/cyassl/ctaocrypt/settings.h +++ b/cyassl/ctaocrypt/settings.h @@ -78,6 +78,9 @@ /* Uncomment next line if using Comverge settings */ /* #define COMVERGE */ +/* Uncomment next line if using QL SEP settings */ +/* #define CYASSL_QL */ + #include @@ -524,6 +527,37 @@ #endif /* MICRIUM */ +#ifdef CYASSL_QL + #ifndef CYASSL_SEP + #define CYASSL_SEP + #endif + #ifndef OPENSSL_EXTRA + #define OPENSSL_EXTRA + #endif + #ifndef SESSION_CERTS + #define SESSION_CERTS + #endif + #ifndef HAVE_AESCCM + #define HAVE_AESCCM + #endif + #ifndef ATOMIC_USER + #define ATOMIC_USER + #endif + #ifndef CYASSL_DER_LOAD + #define CYASSL_DER_LOAD + #endif + #ifndef KEEP_PEER_CERT + #define KEEP_PEER_CERT + #endif + #ifndef HAVE_ECC + #define HAVE_ECC + #endif + #ifndef SESSION_INDEX + #define SESSION_INDEX + #endif +#endif /* CYASSL_QL */ + + #if !defined(XMALLOC_USER) && !defined(MICRIUM_MALLOC) && \ !defined(CYASSL_LEANPSK) && !defined(NO_CYASSL_MEMORY) #define USE_CYASSL_MEMORY diff --git a/cyassl/internal.h b/cyassl/internal.h index 32b8964bf..527a3f380 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1661,6 +1661,10 @@ struct CYASSL_X509 { byte hwType[EXTERNAL_SERIAL_SIZE]; int hwSerialNumSz; byte hwSerialNum[EXTERNAL_SERIAL_SIZE]; + #ifdef OPENSSL_EXTRA + byte certPolicySet; + byte certPolicyCrit; + #endif /* OPENSSL_EXTRA */ #endif int notBeforeSz; byte notBefore[MAX_DATE_SZ]; @@ -1670,10 +1674,31 @@ struct CYASSL_X509 { buffer sig; int pubKeyOID; buffer pubKey; + #ifdef HAVE_ECC + word32 pkCurveOID; + #endif /* HAVE_ECC */ buffer derCert; /* may need */ DNS_entry* altNames; /* alt names list */ DNS_entry* altNamesNext; /* hint for retrieval */ byte dynamicMemory; /* dynamic memory flag */ + byte isCa; +#ifdef OPENSSL_EXTRA + word32 pathLength; + word16 keyUsage; + byte basicConstSet; + byte basicConstCrit; + byte basicConstPlSet; + byte subjAltNameSet; + byte subjAltNameCrit; + byte authKeyIdSet; + byte authKeyIdCrit; + byte authKeyId[SHA_SIZE]; + byte subjKeyIdSet; + byte subjKeyIdCrit; + byte subjKeyId[SHA_SIZE]; + byte keyUsageSet; + byte keyUsageCrit; +#endif /* OPENSSL_EXTRA */ }; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index bd5f25c38..6e2e0a889 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -99,6 +99,9 @@ typedef struct CYASSL_EVP_PKEY { union { char* ptr; } pkey; + #ifdef HAVE_ECC + int pkey_curve; + #endif } CYASSL_EVP_PKEY; typedef struct CYASSL_MD4_CTX { @@ -413,6 +416,16 @@ CYASSL_API int CyaSSL_X509_STORE_CTX_get_error_depth(CYASSL_X509_STORE_CTX*); CYASSL_API char* CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME*, char*, int); CYASSL_API CYASSL_X509_NAME* CyaSSL_X509_get_issuer_name(CYASSL_X509*); CYASSL_API CYASSL_X509_NAME* CyaSSL_X509_get_subject_name(CYASSL_X509*); +CYASSL_API int CyaSSL_X509_ext_isSet_by_NID(CYASSL_X509*, int); +CYASSL_API int CyaSSL_X509_ext_get_critical_by_NID(CYASSL_X509*, int); +CYASSL_API int CyaSSL_X509_get_isCA(CYASSL_X509*); +CYASSL_API int CyaSSL_X509_get_isSet_pathLength(CYASSL_X509*); +CYASSL_API unsigned int CyaSSL_X509_get_pathLength(CYASSL_X509*); +CYASSL_API unsigned int CyaSSL_X509_get_keyUsage(CYASSL_X509*); +CYASSL_API unsigned char* CyaSSL_X509_get_authorityKeyID( + CYASSL_X509*, unsigned char*, int*); +CYASSL_API unsigned char* CyaSSL_X509_get_subjectKeyID( + CYASSL_X509*, unsigned char*, int*); CYASSL_API int CyaSSL_X509_NAME_entry_count(CYASSL_X509_NAME*); CYASSL_API int CyaSSL_X509_NAME_get_text_by_NID( CYASSL_X509_NAME*, int, char*, int); diff --git a/src/internal.c b/src/internal.c index 53e0645ec..21cb6b743 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1271,6 +1271,31 @@ void InitX509(CYASSL_X509* x509, int dynamicFlag) x509->altNames = NULL; x509->altNamesNext = NULL; x509->dynamicMemory = (byte)dynamicFlag; + x509->isCa = 0; +#ifdef OPENSSL_EXTRA + x509->pathLength = 0; + x509->basicConstSet = 0; + x509->basicConstCrit = 0; + x509->basicConstPlSet = 0; + x509->subjAltNameSet = 0; + x509->subjAltNameCrit = 0; + x509->authKeyIdSet = 0; + x509->authKeyIdCrit = 0; + XMEMSET(x509->authKeyId, 0, SHA_SIZE); + x509->subjKeyIdSet = 0; + x509->subjKeyIdCrit = 0; + XMEMSET(x509->subjKeyId, 0, SHA_SIZE); + x509->keyUsageSet = 0; + x509->keyUsageCrit = 0; + x509->keyUsage = 0; + #ifdef HAVE_ECC + x509->pkCurveOID = 0; + #endif /* HAVE_ECC */ + #ifdef CYASSL_SEP + x509->certPolicySet = 0; + x509->certPolicyCrit = 0; + #endif /* CYASSL_SEP */ +#endif /* OPENSSL_EXTRA */ } @@ -3156,6 +3181,33 @@ int CopyDecodedToX509(CYASSL_X509* x509, DecodedCert* dCert) dCert->altNames = NULL; /* takes ownership */ x509->altNamesNext = x509->altNames; /* index hint */ + x509->isCa = dCert->isCA; +#ifdef OPENSSL_EXTRA + x509->pathLength = dCert->pathLength; + x509->keyUsage = dCert->extKeyUsage; + + x509->basicConstSet = dCert->extBasicConstSet; + x509->basicConstCrit = dCert->extBasicConstCrit; + x509->basicConstPlSet = dCert->extBasicConstPlSet; + x509->subjAltNameSet = dCert->extSubjAltNameSet; + x509->subjAltNameCrit = dCert->extSubjAltNameCrit; + x509->authKeyIdSet = dCert->extAuthKeyIdSet; + x509->authKeyIdCrit = dCert->extAuthKeyIdCrit; + XMEMCPY(x509->authKeyId, dCert->extAuthKeyId, SHA_SIZE); + x509->subjKeyIdSet = dCert->extSubjKeyIdSet; + x509->subjKeyIdCrit = dCert->extSubjKeyIdCrit; + XMEMCPY(x509->subjKeyId, dCert->extSubjKeyId, SHA_SIZE); + x509->keyUsageSet = dCert->extKeyUsageSet; + x509->keyUsageCrit = dCert->extKeyUsageCrit; + #ifdef HAVE_ECC + x509->pkCurveOID = dCert->pkCurveOID; + #endif /* HAVE_ECC */ + #ifdef CYASSL_SEP + x509->certPolicySet = dCert->extCertPolicySet; + x509->certPolicyCrit = dCert->extCertPolicyCrit; + #endif /* CYASSL_SEP */ +#endif /* OPENSSL_EXTRA */ + return ret; } diff --git a/src/ssl.c b/src/ssl.c index 7da7f2224..8ae90d350 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -7092,6 +7092,170 @@ int CyaSSL_set_compression(CYASSL* ssl) } +#ifdef OPENSSL_EXTRA + int CyaSSL_X509_ext_isSet_by_NID(CYASSL_X509* x509, int nid) + { + int isSet = 0; + + CYASSL_ENTER("CyaSSL_X509_ext_isSet_by_NID"); + + if (x509 != NULL) { + switch (nid) { + case BASIC_CA_OID: isSet = x509->basicConstSet; break; + case ALT_NAMES_OID: isSet = x509->subjAltNameSet; break; + case AUTH_KEY_OID: isSet = x509->authKeyIdSet; break; + case SUBJ_KEY_OID: isSet = x509->subjKeyIdSet; break; + case KEY_USAGE_OID: isSet = x509->keyUsageSet; break; + #ifdef CYASSL_SEP + case CERT_POLICY_OID: isSet = x509->certPolicySet; break; + #endif /* CYASSL_SEP */ + } + } + + CYASSL_LEAVE("CyaSSL_X509_ext_isSet_by_NID", isSet); + + return isSet; + } + + + int CyaSSL_X509_ext_get_critical_by_NID(CYASSL_X509* x509, int nid) + { + int crit = 0; + + CYASSL_ENTER("CyaSSL_X509_ext_get_critical_by_NID"); + + if (x509 != NULL) { + switch (nid) { + case BASIC_CA_OID: crit = x509->basicConstCrit; break; + case ALT_NAMES_OID: crit = x509->subjAltNameCrit; break; + case AUTH_KEY_OID: crit = x509->authKeyIdCrit; break; + case SUBJ_KEY_OID: crit = x509->subjKeyIdCrit; break; + case KEY_USAGE_OID: crit = x509->keyUsageCrit; break; + #ifdef CYASSL_SEP + case CERT_POLICY_OID: crit = x509->certPolicyCrit; break; + #endif /* CYASSL_SEP */ + } + } + + CYASSL_LEAVE("CyaSSL_X509_ext_get_critical_by_NID", crit); + + return crit; + } +#endif + + + int CyaSSL_X509_get_isCA(CYASSL_X509* x509) + { + int isCA = 0; + + CYASSL_ENTER("CyaSSL_X509_get_isCA"); + + if (x509 != NULL) + isCA = x509->isCa; + + CYASSL_LEAVE("CyaSSL_X509_get_isCA", isCA); + + return isCA; + } + + +#ifdef OPENSSL_EXTRA + int CyaSSL_X509_get_isSet_pathLength(CYASSL_X509* x509) + { + int isSet = 0; + + CYASSL_ENTER("CyaSSL_X509_get_isSet_pathLength"); + + if (x509 != NULL) + isSet = x509->basicConstPlSet; + + CYASSL_LEAVE("CyaSSL_X509_get_isSet_pathLength", isSet); + + return isSet; + } + + + word32 CyaSSL_X509_get_pathLength(CYASSL_X509* x509) + { + word32 pathLength = 0; + + CYASSL_ENTER("CyaSSL_X509_get_pathLength"); + + if (x509 != NULL) + pathLength = x509->pathLength; + + CYASSL_LEAVE("CyaSSL_X509_get_pathLength", pathLength); + + return pathLength; + } + + + unsigned int CyaSSL_X509_get_keyUsage(CYASSL_X509* x509) + { + word16 usage = 0; + + CYASSL_ENTER("CyaSSL_X509_get_keyUsage"); + + if (x509 != NULL) + usage = x509->keyUsage; + + CYASSL_LEAVE("CyaSSL_X509_get_keyUsage", usage); + + return usage; + } + + + byte* CyaSSL_X509_get_authorityKeyID( + CYASSL_X509* x509, byte* dst, int* dstLen) + { + byte *id = NULL; + int copySz = min(dstLen != NULL ? *dstLen : 0, SHA_SIZE); + + CYASSL_ENTER("CyaSSL_X509_get_authorityKeyID"); + + if (x509 != NULL) { + if (x509->authKeyIdSet) + id = x509->authKeyId; + + if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) { + XMEMCPY(dst, id, copySz); + id = dst; + *dstLen = copySz; + } + } + + CYASSL_LEAVE("CyaSSL_X509_get_authorityKeyID", copySz); + + return id; + } + + + byte* CyaSSL_X509_get_subjectKeyID( + CYASSL_X509* x509, byte* dst, int* dstLen) + { + byte *id = NULL; + int copySz = min(dstLen != NULL ? *dstLen : 0, SHA_SIZE); + + CYASSL_ENTER("CyaSSL_X509_get_subjectKeyID"); + + if (x509 != NULL) { + if (x509->subjKeyIdSet) + id = x509->subjKeyId; + + if (dst != NULL && dstLen != NULL && id != NULL && copySz > 0) { + XMEMCPY(dst, id, copySz); + id = dst; + *dstLen = copySz; + } + } + + CYASSL_LEAVE("CyaSSL_X509_get_subjectKeyID", copySz); + + return id; + } +#endif + + /* copy name into in buffer, at most sz bytes, if buffer is null will malloc buffer, call responsible for freeing */ char* CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME* name, char* in, int sz) @@ -8373,6 +8537,9 @@ CYASSL_X509* CyaSSL_X509_load_certificate_file(const char* fname, int format) XMEMCPY(key->pkey.ptr, x509->pubKey.buffer, x509->pubKey.length); key->pkey_sz = x509->pubKey.length; + #ifdef HAVE_ECC + key->pkey_curve = (int)x509->pkCurveOID; + #endif /* HAVE_ECC */ } } return key;