internal.c: refactoring DoCertificate to reduce stack usage:

--- variable domain moved to the heap (256 bytes saved)
--- variable dCert moved to the heap (sizeof(DecodedCert) saved)
--- variable store moved to the heap (sizeof(CYASSL_X509_STORE_CTX) saved)
This commit is contained in:
Moisés Guimarães 2014-10-17 16:16:50 -03:00
parent 37c1627234
commit 5ef9a21eaa

View File

@ -4035,14 +4035,24 @@ int CopyDecodedToX509(CYASSL_X509* x509, DecodedCert* dCert)
static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx, static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
word32 size) word32 size)
{ {
word32 listSz, begin = *inOutIdx; word32 listSz;
word32 begin = *inOutIdx;
int ret = 0; int ret = 0;
int anyError = 0; int anyError = 0;
int totalCerts = 0; /* number of certs in certs buffer */ int totalCerts = 0; /* number of certs in certs buffer */
int count; int count;
char domain[ASN_NAME_MAX];
buffer certs[MAX_CHAIN_DEPTH]; buffer certs[MAX_CHAIN_DEPTH];
#ifdef CYASSL_SMALL_STACK
char* domain = NULL;
DecodedCert* dCert = NULL;
CYASSL_X509_STORE_CTX* store = NULL;
#else
char domain[ASN_NAME_MAX];
DecodedCert dCert[1];
CYASSL_X509_STORE_CTX store[1];
#endif
#ifdef CYASSL_CALLBACKS #ifdef CYASSL_CALLBACKS
if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo); if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
@ -4109,22 +4119,28 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
count = totalCerts; count = totalCerts;
#ifdef CYASSL_SMALL_STACK
dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (dCert == NULL)
return MEMORY_E;
#endif
/* verify up to peer's first */ /* verify up to peer's first */
while (count > 1) { while (count > 1) {
buffer myCert = certs[count - 1]; buffer myCert = certs[count - 1];
DecodedCert dCert;
byte* subjectHash; byte* subjectHash;
InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
ssl->ctx->cm); ssl->ctx->cm);
#ifndef NO_SKID #ifndef NO_SKID
subjectHash = dCert.extSubjKeyId; subjectHash = dCert->extSubjKeyId;
#else #else
subjectHash = dCert.subjectHash; subjectHash = dCert->subjectHash;
#endif #endif
if (ret == 0 && dCert.isCA == 0) { if (ret == 0 && dCert->isCA == 0) {
CYASSL_MSG("Chain cert is not a CA, not adding as one"); CYASSL_MSG("Chain cert is not a CA, not adding as one");
} }
else if (ret == 0 && ssl->options.verifyNone) { else if (ret == 0 && ssl->options.verifyNone) {
@ -4155,7 +4171,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_CRL #ifdef HAVE_CRL
if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { if (ret == 0 && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) {
CYASSL_MSG("Doing Non Leaf CRL check"); CYASSL_MSG("Doing Non Leaf CRL check");
ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
if (ret != 0) { if (ret != 0) {
CYASSL_MSG("\tCRL check not ok"); CYASSL_MSG("\tCRL check not ok");
@ -4166,20 +4182,19 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
if (ret != 0 && anyError == 0) if (ret != 0 && anyError == 0)
anyError = ret; /* save error from last time */ anyError = ret; /* save error from last time */
FreeDecodedCert(&dCert); FreeDecodedCert(dCert);
count--; count--;
} }
/* peer's, may not have one if blank client cert sent by TLSv1.2 */ /* peer's, may not have one if blank client cert sent by TLSv1.2 */
if (count) { if (count) {
buffer myCert = certs[0]; buffer myCert = certs[0];
DecodedCert dCert; int fatal = 0;
int fatal = 0;
CYASSL_MSG("Verifying Peer's cert"); CYASSL_MSG("Verifying Peer's cert");
InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); InitDecodedCert(dCert, myCert.buffer, myCert.length, ssl->heap);
ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, ret = ParseCertRelative(dCert, CERT_TYPE, !ssl->options.verifyNone,
ssl->ctx->cm); ssl->ctx->cm);
if (ret == 0) { if (ret == 0) {
CYASSL_MSG("Verified Peer's cert"); CYASSL_MSG("Verified Peer's cert");
@ -4207,7 +4222,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
if (ssl->keys.encryptionOn) { if (ssl->keys.encryptionOn) {
/* compare against previous time */ /* compare against previous time */
if (XMEMCMP(dCert.subjectHash, if (XMEMCMP(dCert->subjectHash,
ssl->secure_renegotiation->subject_hash, ssl->secure_renegotiation->subject_hash,
SHA_DIGEST_SIZE) != 0) { SHA_DIGEST_SIZE) != 0) {
CYASSL_MSG("Peer sent different cert during scr, fatal"); CYASSL_MSG("Peer sent different cert during scr, fatal");
@ -4219,14 +4234,14 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
/* cache peer's hash */ /* cache peer's hash */
if (fatal == 0) { if (fatal == 0) {
XMEMCPY(ssl->secure_renegotiation->subject_hash, XMEMCPY(ssl->secure_renegotiation->subject_hash,
dCert.subjectHash, SHA_DIGEST_SIZE); dCert->subjectHash, SHA_DIGEST_SIZE);
} }
} }
#endif #endif
#ifdef HAVE_OCSP #ifdef HAVE_OCSP
if (fatal == 0 && ssl->ctx->cm->ocspEnabled) { if (fatal == 0 && ssl->ctx->cm->ocspEnabled) {
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, &dCert); ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
if (ret != 0) { if (ret != 0) {
CYASSL_MSG("\tOCSP Lookup not ok"); CYASSL_MSG("\tOCSP Lookup not ok");
fatal = 0; fatal = 0;
@ -4246,7 +4261,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
if (doCrlLookup) { if (doCrlLookup) {
CYASSL_MSG("Doing Leaf CRL check"); CYASSL_MSG("Doing Leaf CRL check");
ret = CheckCertCRL(ssl->ctx->cm->crl, &dCert); ret = CheckCertCRL(ssl->ctx->cm->crl, dCert);
if (ret != 0) { if (ret != 0) {
CYASSL_MSG("\tCRL check not ok"); CYASSL_MSG("\tCRL check not ok");
@ -4260,37 +4275,37 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#ifdef KEEP_PEER_CERT #ifdef KEEP_PEER_CERT
{ {
/* set X509 format for peer cert even if fatal */ /* set X509 format for peer cert even if fatal */
int copyRet = CopyDecodedToX509(&ssl->peerCert, &dCert); int copyRet = CopyDecodedToX509(&ssl->peerCert, dCert);
if (copyRet == MEMORY_E) if (copyRet == MEMORY_E)
fatal = 1; fatal = 1;
} }
#endif #endif
#ifndef IGNORE_KEY_EXTENSIONS #ifndef IGNORE_KEY_EXTENSIONS
if (dCert.extKeyUsageSet) { if (dCert->extKeyUsageSet) {
if ((ssl->specs.kea == rsa_kea) && if ((ssl->specs.kea == rsa_kea) &&
(dCert.extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) { (dCert->extKeyUsage & KEYUSE_KEY_ENCIPHER) == 0) {
ret = KEYUSE_ENCIPHER_E; ret = KEYUSE_ENCIPHER_E;
} }
if ((ssl->specs.sig_algo == rsa_sa_algo || if ((ssl->specs.sig_algo == rsa_sa_algo ||
(ssl->specs.sig_algo == ecc_dsa_sa_algo && (ssl->specs.sig_algo == ecc_dsa_sa_algo &&
!ssl->specs.static_ecdh)) && !ssl->specs.static_ecdh)) &&
(dCert.extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) { (dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) {
CYASSL_MSG("KeyUse Digital Sig not set"); CYASSL_MSG("KeyUse Digital Sig not set");
ret = KEYUSE_SIGNATURE_E; ret = KEYUSE_SIGNATURE_E;
} }
} }
if (dCert.extExtKeyUsageSet) { if (dCert->extExtKeyUsageSet) {
if (ssl->options.side == CYASSL_CLIENT_END) { if (ssl->options.side == CYASSL_CLIENT_END) {
if ((dCert.extExtKeyUsage & if ((dCert->extExtKeyUsage &
(EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) { (EXTKEYUSE_ANY | EXTKEYUSE_SERVER_AUTH)) == 0) {
CYASSL_MSG("ExtKeyUse Server Auth not set"); CYASSL_MSG("ExtKeyUse Server Auth not set");
ret = EXTKEYUSE_AUTH_E; ret = EXTKEYUSE_AUTH_E;
} }
} }
else { else {
if ((dCert.extExtKeyUsage & if ((dCert->extExtKeyUsage &
(EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) { (EXTKEYUSE_ANY | EXTKEYUSE_CLIENT_AUTH)) == 0) {
CYASSL_MSG("ExtKeyUse Client Auth not set"); CYASSL_MSG("ExtKeyUse Client Auth not set");
ret = EXTKEYUSE_AUTH_E; ret = EXTKEYUSE_AUTH_E;
@ -4300,25 +4315,36 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#endif /* IGNORE_KEY_EXTENSIONS */ #endif /* IGNORE_KEY_EXTENSIONS */
if (fatal) { if (fatal) {
FreeDecodedCert(&dCert); FreeDecodedCert(dCert);
#ifdef CYASSL_SMALL_STACK
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
ssl->error = ret; ssl->error = ret;
return ret; return ret;
} }
ssl->options.havePeerCert = 1; ssl->options.havePeerCert = 1;
#ifdef CYASSL_SMALL_STACK
domain = (char*)XMALLOC(ASN_NAME_MAX, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (domain == NULL) {
FreeDecodedCert(dCert);
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
/* store for callback use */ /* store for callback use */
if (dCert.subjectCNLen < ASN_NAME_MAX) { if (dCert->subjectCNLen < ASN_NAME_MAX) {
XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen); XMEMCPY(domain, dCert->subjectCN, dCert->subjectCNLen);
domain[dCert.subjectCNLen] = '\0'; domain[dCert->subjectCNLen] = '\0';
} }
else else
domain[0] = '\0'; domain[0] = '\0';
if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) { if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) {
if (MatchDomainName(dCert.subjectCN, dCert.subjectCNLen, if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
(char*)ssl->buffers.domainName.buffer) == 0) { (char*)ssl->buffers.domainName.buffer) == 0) {
CYASSL_MSG("DomainName match on common name failed"); CYASSL_MSG("DomainName match on common name failed");
if (CheckAltNames(&dCert, if (CheckAltNames(dCert,
(char*)ssl->buffers.domainName.buffer) == 0 ) { (char*)ssl->buffers.domainName.buffer) == 0 ) {
CYASSL_MSG("DomainName match on alt names failed too"); CYASSL_MSG("DomainName match on alt names failed too");
ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */ ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */
@ -4327,7 +4353,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
} }
/* decode peer key */ /* decode peer key */
switch (dCert.keyOID) { switch (dCert->keyOID) {
#ifndef NO_RSA #ifndef NO_RSA
case RSAk: case RSAk:
{ {
@ -4340,8 +4366,8 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
keyRet = InitRsaKey(ssl->peerRsaKey, ssl->heap); keyRet = InitRsaKey(ssl->peerRsaKey, ssl->heap);
} }
if (keyRet != 0 || RsaPublicKeyDecode(dCert.publicKey, &idx, if (keyRet != 0 || RsaPublicKeyDecode(dCert->publicKey,
ssl->peerRsaKey, dCert.pubKeySize) != 0) { &idx, ssl->peerRsaKey, dCert->pubKeySize) != 0) {
ret = PEER_KEY_ERROR; ret = PEER_KEY_ERROR;
} }
else { else {
@ -4349,15 +4375,15 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifndef NO_RSA #ifndef NO_RSA
ssl->buffers.peerRsaKey.buffer = ssl->buffers.peerRsaKey.buffer =
XMALLOC(dCert.pubKeySize, XMALLOC(dCert->pubKeySize,
ssl->heap, DYNAMIC_TYPE_RSA); ssl->heap, DYNAMIC_TYPE_RSA);
if (ssl->buffers.peerRsaKey.buffer == NULL) if (ssl->buffers.peerRsaKey.buffer == NULL)
ret = MEMORY_ERROR; ret = MEMORY_ERROR;
else { else {
XMEMCPY(ssl->buffers.peerRsaKey.buffer, XMEMCPY(ssl->buffers.peerRsaKey.buffer,
dCert.publicKey, dCert.pubKeySize); dCert->publicKey, dCert->pubKeySize);
ssl->buffers.peerRsaKey.length = ssl->buffers.peerRsaKey.length =
dCert.pubKeySize; dCert->pubKeySize;
} }
#endif /* NO_RSA */ #endif /* NO_RSA */
#endif /*HAVE_PK_CALLBACKS */ #endif /*HAVE_PK_CALLBACKS */
@ -4368,12 +4394,13 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_NTRU #ifdef HAVE_NTRU
case NTRUk: case NTRUk:
{ {
if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) { if (dCert->pubKeySize > sizeof(ssl->peerNtruKey)) {
ret = PEER_KEY_ERROR; ret = PEER_KEY_ERROR;
} }
else { else {
XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize); XMEMCPY(ssl->peerNtruKey, dCert->publicKey,
ssl->peerNtruKeyLen = (word16)dCert.pubKeySize; dCert->pubKeySize);
ssl->peerNtruKeyLen = (word16)dCert->pubKeySize;
ssl->peerNtruKeyPresent = 1; ssl->peerNtruKeyPresent = 1;
} }
} }
@ -4387,7 +4414,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
ssl->peerEccDsaKeyPresent = 0; ssl->peerEccDsaKeyPresent = 0;
ecc_init(ssl->peerEccDsaKey); ecc_init(ssl->peerEccDsaKey);
} }
if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize, if (ecc_import_x963(dCert->publicKey, dCert->pubKeySize,
ssl->peerEccDsaKey) != 0) { ssl->peerEccDsaKey) != 0) {
ret = PEER_KEY_ERROR; ret = PEER_KEY_ERROR;
} }
@ -4396,15 +4423,15 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifdef HAVE_ECC #ifdef HAVE_ECC
ssl->buffers.peerEccDsaKey.buffer = ssl->buffers.peerEccDsaKey.buffer =
XMALLOC(dCert.pubKeySize, XMALLOC(dCert->pubKeySize,
ssl->heap, DYNAMIC_TYPE_ECC); ssl->heap, DYNAMIC_TYPE_ECC);
if (ssl->buffers.peerEccDsaKey.buffer == NULL) if (ssl->buffers.peerEccDsaKey.buffer == NULL)
ret = MEMORY_ERROR; ret = MEMORY_ERROR;
else { else {
XMEMCPY(ssl->buffers.peerEccDsaKey.buffer, XMEMCPY(ssl->buffers.peerEccDsaKey.buffer,
dCert.publicKey, dCert.pubKeySize); dCert->publicKey, dCert->pubKeySize);
ssl->buffers.peerEccDsaKey.length = ssl->buffers.peerEccDsaKey.length =
dCert.pubKeySize; dCert->pubKeySize;
} }
#endif /* HAVE_ECC */ #endif /* HAVE_ECC */
#endif /*HAVE_PK_CALLBACKS */ #endif /*HAVE_PK_CALLBACKS */
@ -4416,42 +4443,52 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
break; break;
} }
FreeDecodedCert(&dCert); FreeDecodedCert(dCert);
} }
#ifdef CYASSL_SMALL_STACK
XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
store = (CYASSL_X509_STORE_CTX*)XMALLOC(sizeof(CYASSL_X509_STORE_CTX),
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (store == NULL) {
XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
if (anyError != 0 && ret == 0) if (anyError != 0 && ret == 0)
ret = anyError; ret = anyError;
if (ret != 0) { if (ret != 0) {
if (!ssl->options.verifyNone) { if (!ssl->options.verifyNone) {
int why = bad_certificate; int why = bad_certificate;
if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E)
why = certificate_expired; why = certificate_expired;
if (ssl->verifyCallback) { if (ssl->verifyCallback) {
int ok; int ok;
CYASSL_X509_STORE_CTX store;
store.error = ret; store->error = ret;
store.error_depth = totalCerts; store->error_depth = totalCerts;
store.discardSessionCerts = 0; store->discardSessionCerts = 0;
store.domain = domain; store->domain = domain;
store.userCtx = ssl->verifyCbCtx; store->userCtx = ssl->verifyCbCtx;
#ifdef KEEP_PEER_CERT #ifdef KEEP_PEER_CERT
store.current_cert = &ssl->peerCert; store->current_cert = &ssl->peerCert;
#else #else
store.current_cert = NULL; store->current_cert = NULL;
#endif #endif
#ifdef FORTRESS #ifdef FORTRESS
store.ex_data = ssl; store->ex_data = ssl;
#endif #endif
ok = ssl->verifyCallback(0, &store); ok = ssl->verifyCallback(0, store);
if (ok) { if (ok) {
CYASSL_MSG("Verify callback overriding error!"); CYASSL_MSG("Verify callback overriding error!");
ret = 0; ret = 0;
} }
#ifdef SESSION_CERTS #ifdef SESSION_CERTS
if (store.discardSessionCerts) { if (store->discardSessionCerts) {
CYASSL_MSG("Verify callback requested discard sess certs"); CYASSL_MSG("Verify callback requested discard sess certs");
ssl->session.chain.count = 0; ssl->session.chain.count = 0;
} }
@ -4468,19 +4505,18 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
else { else {
if (ssl->verifyCallback) { if (ssl->verifyCallback) {
int ok; int ok;
CYASSL_X509_STORE_CTX store;
store.error = ret; store->error = ret;
store.error_depth = totalCerts; store->error_depth = totalCerts;
store.discardSessionCerts = 0; store->discardSessionCerts = 0;
store.domain = domain; store->domain = domain;
store.userCtx = ssl->verifyCbCtx; store->userCtx = ssl->verifyCbCtx;
#ifdef KEEP_PEER_CERT #ifdef KEEP_PEER_CERT
store.current_cert = &ssl->peerCert; store->current_cert = &ssl->peerCert;
#endif #endif
store.ex_data = ssl; store->ex_data = ssl;
ok = ssl->verifyCallback(1, &store); ok = ssl->verifyCallback(1, store);
if (!ok) { if (!ok) {
CYASSL_MSG("Verify callback overriding valid certificate!"); CYASSL_MSG("Verify callback overriding valid certificate!");
ret = -1; ret = -1;
@ -4488,7 +4524,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
ssl->options.isClosed = 1; ssl->options.isClosed = 1;
} }
#ifdef SESSION_CERTS #ifdef SESSION_CERTS
if (store.discardSessionCerts) { if (store->discardSessionCerts) {
CYASSL_MSG("Verify callback requested discard sess certs"); CYASSL_MSG("Verify callback requested discard sess certs");
ssl->session.chain.count = 0; ssl->session.chain.count = 0;
} }
@ -4510,6 +4546,11 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx,
*inOutIdx += ssl->keys.padSz; *inOutIdx += ssl->keys.padSz;
} }
#ifdef CYASSL_SMALL_STACK
XFREE(store, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(domain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret; return ret;
} }