diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 8597fa238..205310bf3 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -6493,6 +6493,12 @@ int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm) if (ca) { CYASSL_MSG("Found CRL issuer CA"); /* try to confirm/verify signature */ + #ifndef IGNORE_KEY_EXTENSIONS + if ((ca->keyUsage & KEYUSE_CRL_SIGN) == 0) { + CYASSL_MSG("CA cannot sign CRLs"); + return ASN_CRL_NO_SIGNER_E; + } + #endif /* IGNORE_KEY_EXTENSIONS */ if (!ConfirmSignature(buff + dcrl->certBegin, dcrl->sigIndex - dcrl->certBegin, ca->publicKey, ca->pubKeySize, ca->keyOID, diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index fe961afdb..751739dd7 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -426,6 +426,7 @@ struct DecodedCert { struct Signer { word32 pubKeySize; word32 keyOID; /* key type */ + word16 keyUsage; byte* publicKey; int nameLen; char* name; /* common name */ diff --git a/cyassl/error-ssl.h b/cyassl/error-ssl.h index 71f4b4ffd..134c0e6a7 100644 --- a/cyassl/error-ssl.h +++ b/cyassl/error-ssl.h @@ -115,6 +115,10 @@ enum CyaSSL_ErrorCodes { UNKNOWN_SNI_HOST_NAME_E = -281, /* Unrecognized host name Error */ UNKNOWN_MAX_FRAG_LEN_E = -282, /* Unrecognized max frag len Error */ /* add strings to SetErrorString !!!!! */ + KEYUSE_SIGNATURE_E = -283, /* KeyUse digSignature error */ + KEYUSE_AGREEMENT_E = -284, /* KeyUse keyAgreement error */ + KEYUSE_ENCIPHER_E = -285, /* KeyUse keyEncipher error */ + EXTKEYUSE_AUTH_E = -286, /* ExtKeyUse server|client_auth */ /* begin negotiation parameter errors */ UNSUPPORTED_SUITE = -290, /* unsupported cipher suite */ diff --git a/src/internal.c b/src/internal.c index 044342304..dac18b89f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3465,6 +3465,49 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx, } #endif +#ifndef IGNORE_KEY_EXTENSIONS + if (dCert.extKeyUsageSet) { + if ((ssl->specs.kea == rsa_kea) && + (dCert.extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { + fatal = 1; + ret = KEYUSE_ENCIPHER_E; + } + if ((ssl->specs.kea == diffie_hellman_kea || + ssl->specs.kea == ecc_diffie_hellman_kea || + ssl->specs.kea == ecc_static_diffie_hellman_kea) && + (dCert.extKeyUsage & KEYUSE_KEY_AGREE) == 0) { + fatal = 1; + ret = KEYUSE_AGREEMENT_E; + } + if ((ssl->specs.sig_algo == rsa_sa_algo || + ssl->specs.sig_algo == ecc_dsa_sa_algo) && + (dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { + CYASSL_MSG("KeyUse Digital Sig not set"); + fatal = 1; + ret = KEYUSE_SIGNATURE_E; + } + } + + if (dCert.extExtKeyUsageSet) { + if (ssl->options.side == CYASSL_CLIENT_END) { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Server Auth not set"); + fatal = 1; + ret = EXTKEYUSE_AUTH_E; + } + } + else { + if ((dCert.extExtKeyUsage & + (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { + CYASSL_MSG("ExtKeyUse Client Auth not set"); + fatal = 1; + ret = EXTKEYUSE_AUTH_E; + } + } + } +#endif /* IGNORE_KEY_EXTENSIONS */ + if (fatal) { FreeDecodedCert(&dCert); ssl->error = ret; @@ -6451,6 +6494,22 @@ void SetErrorString(int error, char* str) XSTRNCPY(str, "Unrecognized host name Error", max); break; + case KEYUSE_SIGNATURE_E: + XSTRNCPY(str, "Key Use digitalSignature not set Error", max); + break; + + case KEYUSE_AGREEMENT_E: + XSTRNCPY(str, "Key Use keyAgreement not set Error", max); + break; + + case KEYUSE_ENCIPHER_E: + XSTRNCPY(str, "Key Use keyEncipherment not set Error", max); + break; + + case EXTKEYUSE_AUTH_E: + XSTRNCPY(str, "Ext Key Use server/client auth not set Error", max); + break; + default : XSTRNCPY(str, "unknown error number", max); } diff --git a/src/ssl.c b/src/ssl.c index 17d649863..1bcaa594a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1526,6 +1526,8 @@ int AddCA(CYASSL_CERT_MANAGER* cm, buffer der, int type, int verify) cert.extSubjKeyId, SHA_DIGEST_SIZE); #endif XMEMCPY(signer->subjectNameHash, cert.subjectHash, SHA_DIGEST_SIZE); + signer->keyUsage = cert.extKeyUsageSet ? cert.extKeyUsage : 0xFFFF; + /* If Key Usage not set, all uses valid. */ signer->next = NULL; /* in case lock fails */ cert.publicKey = 0; /* don't free here */