From 831f4b6be9a9bf5450808763fd4ff0c4a213e16d Mon Sep 17 00:00:00 2001 From: Todd A Ouska Date: Sat, 9 Apr 2011 13:08:56 -0700 Subject: [PATCH] add use cert chain handling --- certs/server-cert.pem | 56 +++++++++++++++++++++++++++++++ configure.in | 2 +- ctaocrypt/include/config.h | 2 +- examples/server/server.c | 4 +-- include/cyassl_int.h | 18 +++++++--- include/openssl/ssl.h | 2 +- src/cyassl_int.c | 23 +++++++++++-- src/ssl.c | 68 +++++++++++++++++++++++++++++++++++--- 8 files changed, 159 insertions(+), 16 deletions(-) diff --git a/certs/server-cert.pem b/certs/server-cert.pem index 1ec53c026..9fc28c2f9 100644 --- a/certs/server-cert.pem +++ b/certs/server-cert.pem @@ -37,3 +37,59 @@ Kp5+VqW2h58VxxhmfhZ34qcCAwEAATANBgkqhkiG9w0BAQQFAANBAFipmOcWUkxA 5+FHkhkbOo+XbHu3sMsgba2100dY2OTyPjLp74d35VQ29I1QjQe0d0XqnaQzNpsL 4HRYEcUBe00= -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:37:22:65:73:f5:aa:e8 + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, ST=Montana, L=Bozeman, O=sawtooth, OU=consulting, CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + Validity + Not Before: Jun 30 18:47:10 2010 GMT + Not After : Mar 26 18:47:10 2013 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=sawtooth, OU=consulting, CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (512 bit) + Modulus (512 bit): + 00:97:30:b9:1a:92:ef:25:4f:ca:4c:11:31:95:1a: + e1:c0:10:19:0a:20:b9:37:80:1a:57:38:02:4e:1b: + c5:0f:28:4f:da:e3:c9:16:aa:50:bd:4a:fb:b7:71: + c7:35:cc:63:81:c1:dd:9d:33:f9:38:16:88:32:a0: + aa:56:23:03:a3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 3B:66:FD:A0:40:C6:F4:E2:70:CF:21:1A:0C:4F:67:FE:B7:4B:42:09 + X509v3 Authority Key Identifier: + keyid:3B:66:FD:A0:40:C6:F4:E2:70:CF:21:1A:0C:4F:67:FE:B7:4B:42:09 + DirName:/C=US/ST=Montana/L=Bozeman/O=sawtooth/OU=consulting/CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + serial:8A:37:22:65:73:F5:AA:E8 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 32:65:a2:b1:dc:6d:e0:8d:8b:c8:58:29:8e:b8:18:4b:62:88: + 13:67:f8:6c:75:46:75:8f:8a:19:a6:a3:d5:3c:fc:57:4e:7a: + 68:a9:fc:93:dc:ae:29:7d:bb:4e:ec:ea:55:fa:a4:e3:00:61: + f4:b0:34:6d:d1:d5:a4:64:24:f8 +-----BEGIN CERTIFICATE----- +MIIDQDCCAuqgAwIBAgIJAIo3ImVz9aroMA0GCSqGSIb3DQEBBAUAMIGeMQswCQYD +VQQGEwJVUzEQMA4GA1UECBMHTW9udGFuYTEQMA4GA1UEBxMHQm96ZW1hbjERMA8G +A1UEChMIc2F3dG9vdGgxEzARBgNVBAsTCmNvbnN1bHRpbmcxJDAiBgNVBAMTG3d3 +dy5zYXd0b290aC1jb25zdWx0aW5nLmNvbTEdMBsGCSqGSIb3DQEJARYOaW5mb0B5 +YXNzbC5jb20wHhcNMTAwNjMwMTg0NzEwWhcNMTMwMzI2MTg0NzEwWjCBnjELMAkG +A1UEBhMCVVMxEDAOBgNVBAgTB01vbnRhbmExEDAOBgNVBAcTB0JvemVtYW4xETAP +BgNVBAoTCHNhd3Rvb3RoMRMwEQYDVQQLEwpjb25zdWx0aW5nMSQwIgYDVQQDExt3 +d3cuc2F3dG9vdGgtY29uc3VsdGluZy5jb20xHTAbBgkqhkiG9w0BCQEWDmluZm9A +eWFzc2wuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJcwuRqS7yVPykwRMZUa +4cAQGQoguTeAGlc4Ak4bxQ8oT9rjyRaqUL1K+7dxxzXMY4HB3Z0z+TgWiDKgqlYj +A6MCAwEAAaOCAQcwggEDMB0GA1UdDgQWBBQ7Zv2gQMb04nDPIRoMT2f+t0tCCTCB +0wYDVR0jBIHLMIHIgBQ7Zv2gQMb04nDPIRoMT2f+t0tCCaGBpKSBoTCBnjELMAkG +A1UEBhMCVVMxEDAOBgNVBAgTB01vbnRhbmExEDAOBgNVBAcTB0JvemVtYW4xETAP +BgNVBAoTCHNhd3Rvb3RoMRMwEQYDVQQLEwpjb25zdWx0aW5nMSQwIgYDVQQDExt3 +d3cuc2F3dG9vdGgtY29uc3VsdGluZy5jb20xHTAbBgkqhkiG9w0BCQEWDmluZm9A +eWFzc2wuY29tggkAijciZXP1qugwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQF +AANBADJlorHcbeCNi8hYKY64GEtiiBNn+Gx1RnWPihmmo9U8/FdOemip/JPcril9 +u07s6lX6pOMAYfSwNG3R1aRkJPg= +-----END CERTIFICATE----- diff --git a/configure.in b/configure.in index fa0212633..e2f4b4469 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(cyassl,1.9.5) # !!! also change in ssl.h !!! +AM_INIT_AUTOMAKE(cyassl,1.9.6) # !!! also change in ssl.h !!! AM_CONFIG_HEADER(ctaocrypt/include/config.h) diff --git a/ctaocrypt/include/config.h b/ctaocrypt/include/config.h index 4eecc7199..7230d2c67 100644 --- a/ctaocrypt/include/config.h +++ b/ctaocrypt/include/config.h @@ -79,7 +79,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.9.5" +#define VERSION "1.9.6" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ diff --git a/examples/server/server.c b/examples/server/server.c index b695a38d6..f4d602e26 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -96,9 +96,9 @@ THREAD_RETURN CYASSL_API server_test(void* args) != SSL_SUCCESS) err_sys("can't load ntru key file"); #else /* normal */ - if (SSL_CTX_use_certificate_file(ctx, svrCert, SSL_FILETYPE_PEM) + if (SSL_CTX_use_certificate_chain_file(ctx, svrCert) != SSL_SUCCESS) - err_sys("can't load server cert file"); + err_sys("can't load server cert chain file"); if (SSL_CTX_use_PrivateKey_file(ctx, svrKey, SSL_FILETYPE_PEM) != SSL_SUCCESS) diff --git a/include/cyassl_int.h b/include/cyassl_int.h index ef66af310..9cd7c01d8 100644 --- a/include/cyassl_int.h +++ b/include/cyassl_int.h @@ -92,6 +92,9 @@ typedef byte word24[3]; +/* used by ssl.c and cyassl_int.c */ +void c32to24(word32 in, word24 out); + /* Define or comment out the cipher suites you'd like to be compiled in make sure to use at least one BUILD_SSL_xxx or BUILD_TLS_xxx is defined @@ -576,6 +579,8 @@ struct SSL_CIPHER { struct SSL_CTX { SSL_METHOD* method; buffer certificate; + buffer certChain; + /* chain after self, in DER, with leading size for each cert */ buffer privateKey; Signer* caList; /* SSL_CTX owns this, SSL will reference */ Suites suites; @@ -837,6 +842,8 @@ enum AcceptState { typedef struct Buffers { buffer certificate; /* SSL_CTX owns, unless we own */ buffer key; /* SSL_CTX owns, unless we own */ + buffer certChain; /* SSL_CTX owns */ + /* chain after self, in DER, with leading size for each cert */ buffer domainName; /* for client check */ buffer serverDH_P; buffer serverDH_G; @@ -1029,11 +1036,12 @@ enum { typedef struct EncryptedInfo { - char name[NAME_SZ]; - byte iv[IV_SZ]; - word32 ivSz; - byte set; - SSL_CTX* ctx; + char name[NAME_SZ]; /* encryption name */ + byte iv[IV_SZ]; /* encrypted IV */ + word32 ivSz; /* encrypted IV size */ + long consumed; /* tracks PEM bytes consumed */ + byte set; /* if encryption set */ + SSL_CTX* ctx; /* CTX owner */ } EncryptedInfo; diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 3f83b8f59..7f19fa12f 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -39,7 +39,7 @@ #include "prefix_ssl.h" #endif -#define CYASSL_VERSION "1.9.5" +#define CYASSL_VERSION "1.9.6" #undef X509_NAME /* wincrypt.h clash */ diff --git a/src/cyassl_int.c b/src/cyassl_int.c index d8f2ba484..aa1914298 100644 --- a/src/cyassl_int.c +++ b/src/cyassl_int.c @@ -148,7 +148,8 @@ static byte GetEntropy(ENTROPY_CMD cmd, byte* out) #endif /* HAVE_NTRU */ -static INLINE void c32to24(word32 in, word24 out) +/* used by ssl.c too */ +void c32to24(word32 in, word24 out) { out[0] = (in >> 16) & 0xff; out[1] = (in >> 8) & 0xff; @@ -318,6 +319,7 @@ void InitSSL_Ctx(SSL_CTX* ctx, SSL_METHOD* method) { ctx->method = method; ctx->certificate.buffer = 0; + ctx->certChain.buffer = 0; ctx->privateKey.buffer = 0; ctx->haveDH = 0; ctx->haveNTRU = 0; /* start off */ @@ -376,6 +378,7 @@ void SSL_CtxResourceFree(SSL_CTX* ctx) { XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY); XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT); + XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT); XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); FreeSigners(ctx->caList, ctx->heap); @@ -611,6 +614,7 @@ int InitSSL(SSL* ssl, SSL_CTX* ctx) ssl->buffers.certificate.buffer = 0; ssl->buffers.key.buffer = 0; + ssl->buffers.certChain.buffer = 0; ssl->buffers.inputBuffer.length = 0; ssl->buffers.inputBuffer.idx = 0; ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; @@ -695,8 +699,9 @@ int InitSSL(SSL* ssl, SSL_CTX* ctx) ssl->options.partialWrite = ctx->partialWrite; ssl->options.quietShutdown = ctx->quietShutdown; - /* SSL_CTX still owns certificate, key, and caList buffers */ + /* SSL_CTX still owns certificate, certChain, key, and caList buffers */ ssl->buffers.certificate = ctx->certificate; + ssl->buffers.certChain = ctx->certChain; ssl->buffers.key = ctx->privateKey; ssl->buffers.weOwnCert = 0; ssl->buffers.weOwnKey = 0; @@ -785,6 +790,7 @@ void SSL_ResourceFree(SSL* ssl) XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + /* SSL_CTX always owns certChain */ if (ssl->buffers.weOwnCert) XFREE(ssl->buffers.certificate.buffer, ssl->heap, DYNAMIC_TYPE_CERT); if (ssl->buffers.weOwnKey) @@ -2534,6 +2540,12 @@ int SendCertificate(SSL* ssl) /* list + cert size */ length = certSz + 2 * CERT_HEADER_SZ; listSz = certSz + CERT_HEADER_SZ; + + /* may need to send rest of chain, already has leading size(s) */ + if (ssl->buffers.certChain.buffer) { + length += ssl->buffers.certChain.length; + listSz += ssl->buffers.certChain.length; + } } sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; @@ -2564,6 +2576,13 @@ int SendCertificate(SSL* ssl) i += CERT_HEADER_SZ; XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz); i += certSz; + + /* send rest of chain? */ + if (ssl->buffers.certChain.buffer) { + XMEMCPY(output + i, ssl->buffers.certChain.buffer, + ssl->buffers.certChain.length); + i += ssl->buffers.certChain.length; + } } HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS diff --git a/src/ssl.c b/src/ssl.c index 8e216b368..87f9b4284 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -364,6 +364,8 @@ static int AddCA(SSL_CTX* ctx, buffer der) #endif /* NO_SESSION_CACHE */ + /* Remove PEM header/footer, convert to ASN1, store any encrypted data + info->consumed tracks of PEM bytes consumed in case multiple parts */ static int PemToDer(const unsigned char* buff, long sz, int type, buffer* der, void* heap, EncryptedInfo* info, int* eccKey) { @@ -371,6 +373,7 @@ static int AddCA(SSL_CTX* ctx, buffer der) char footer[PEM_LINE_LEN]; char* headerEnd; char* footerEnd; + char* consumedEnd; long neededSz; int pkcs8 = 0; int pkcs8Enc = 0; @@ -475,6 +478,18 @@ static int AddCA(SSL_CTX* ctx, buffer der) footerEnd = XSTRSTR((char*)buff, footer); if (!footerEnd) return SSL_BAD_FILE; + consumedEnd = footerEnd + XSTRLEN(footer); + + /* get next line */ + if (consumedEnd[0] == '\n') + consumedEnd++; + else if (consumedEnd[1] == '\n') + consumedEnd += 2; + else + return SSL_BAD_FILE; + + info->consumed = (long)(consumedEnd - (char*)buff); + /* set up der buffer */ neededSz = (long)(footerEnd - headerEnd); if (neededSz > sz || neededSz < 0) return SSL_BAD_FILE; @@ -515,9 +530,10 @@ static int AddCA(SSL_CTX* ctx, buffer der) int dynamicType; int eccKey = 0; - info.set = 0; - info.ctx = ctx; - der.buffer = 0; + info.set = 0; + info.ctx = ctx; + info.consumed = 0; + der.buffer = 0; if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM && format != SSL_FILETYPE_RAW) @@ -536,6 +552,50 @@ static int AddCA(SSL_CTX* ctx, buffer der) XFREE(der.buffer, ctx->heap, dynamicType); return ret; } + /* we may have a cert chain */ + if (type == CERT_TYPE && info.consumed < sz) { + /* allow a chain of MAX_DEPTH plus subject, 5 by default */ + byte chainBuffer[MAX_X509_SIZE * MAX_CHAIN_DEPTH]; + long consumed = info.consumed; + word32 idx = 0; + + CYASSL_MSG("Processing Cert Chain"); + while (consumed < sz) { + buffer part; + info.consumed = 0; + part.buffer = 0; + + ret = PemToDer(buff + consumed, sz - consumed, type, &part, + ctx->heap, &info, &eccKey); + if (ret == 0) { + if ( (idx + part.length) > sizeof(chainBuffer)) { + CYASSL_MSG(" Cert Chain bigger than buffer"); + ret = BUFFER_E; + } + else { + c32to24(part.length, &chainBuffer[idx]); + idx += CERT_HEADER_SZ; + XMEMCPY(&chainBuffer[idx], part.buffer,part.length); + idx += part.length; + consumed += info.consumed; + } + } + + XFREE(part.buffer, ctx->heap, dynamicType); + if (ret < 0) { + CYASSL_MSG(" Error in Cert in Chain"); + return ret; + } + CYASSL_MSG(" Consumed another Cert in Chain"); + } + CYASSL_MSG("Finished Processing Cert Chain"); + ctx->certChain.buffer = (byte*)XMALLOC(idx, ctx->heap, + dynamicType); + if (ctx->certChain.buffer == NULL) + return MEMORY_E; + ctx->certChain.length = idx; + XMEMCPY(ctx->certChain.buffer, chainBuffer, idx); + } } else { /* ASN1 (DER) or RAW (NTRU) */ der.buffer = (byte*) XMALLOC(sz, ctx->heap, dynamicType); @@ -830,7 +890,7 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format) int SSL_CTX_use_certificate_chain_file(SSL_CTX* ctx, const char* file) { - /* add first to ctx, all tested implementations support this */ + /* procces up to MAX_CHAIN_DEPTH plus subject cert */ if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CERT_TYPE, NULL) == SSL_SUCCESS) return SSL_SUCCESS;