From 680358abe15f66826e1cb76eafa110fae42c851d Mon Sep 17 00:00:00 2001 From: Todd A Ouska Date: Tue, 22 Mar 2011 07:35:18 -0700 Subject: [PATCH] PKCS #5 v1.5 encrypted key adds, small build fixes --- certs/server-keyPkcs8Enc.pem | 11 +++ certs/taoCert.txt | 7 ++ ctaocrypt/include/asn.h | 15 +++- ctaocrypt/src/asn.c | 165 +++++++++++++++++++++++++++++++++- ctaocrypt/src/ecc.c | 1 + ctaocrypt/src/ecc_fp.c | 1 + include/cyassl_int.h | 11 +-- include/openssl/cyassl_test.h | 6 +- src/cyassl_int.c | 11 +-- src/cyassl_io.c | 2 +- src/ssl.c | 49 ++++++---- 11 files changed, 247 insertions(+), 32 deletions(-) create mode 100644 certs/server-keyPkcs8Enc.pem create mode 100644 ctaocrypt/src/ecc.c create mode 100644 ctaocrypt/src/ecc_fp.c diff --git a/certs/server-keyPkcs8Enc.pem b/certs/server-keyPkcs8Enc.pem new file mode 100644 index 000000000..d8dba0409 --- /dev/null +++ b/certs/server-keyPkcs8Enc.pem @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBgTAbBgkqhkiG9w0BBQMwDgQIMbn/uK6tvZcCAggABIIBYK9oQl9uOmp/LC3j +VxEoo+imbDLwS+ybpjbvcnfyWja4TRpRdCHCB/PLHRmVGCf/pBMG8UkobxbVbjpg +DE5Mr69rOVOreNVIBkfAt0B8PgmLPRdKXtp6Y8IJ85R9Aic1g1+s5XeBcvEZRUHm +ZvKd+oV4y8OUpnZkAZdN4In/8ZvWEfZf6ZPplGbcmoqM7eoLrCCiJ1zLvTt3CPm5 +yi/F8jJxPYM2iNj86y9hlpwk4lS+TvdAwmO/RGQQWverEQmX9MPob23s5ouBdHe5 +7TnBldo/Hq6YVtBYHuvOlx99kaMuumhYdhRONRnWbXedqymaMMG0xA4RgCljv0ud +JrWK1YNGB7gl7/ANoqyy4ZODBUoH33qDR0NzkqwGXMIexlUZIjbwMmUPZZ/XBqMB +tEDrOxAnauE12K3DbfviE40Py8uloXiZf94RnPWbttGp874EOpyiEYjUooo3ii6G +jscqox0= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/certs/taoCert.txt b/certs/taoCert.txt index 41b8c062d..30cf7afc8 100644 --- a/certs/taoCert.txt +++ b/certs/taoCert.txt @@ -69,6 +69,13 @@ openssl rsa -in 1024rsa.priv -pubout -out 1024rsa.pub openssl pkcs8 -nocrypt -topk8 -in server-key.pem -out server-keyPkcs8.pem +**** To convert to pkcs8 encrypted ******* + +openssl pkcs8 -topk8 -in server-key.pem -out server-keyPkcs8Enc.pem + +passwd: yassl123 + + **** To convert from pkcs8 to traditional **** openssl pkcs8 -nocrypt -in server-keyPkcs8.pem -out server-key.pem diff --git a/ctaocrypt/include/asn.h b/ctaocrypt/include/asn.h index 12a874954..24e045006 100644 --- a/ctaocrypt/include/asn.h +++ b/ctaocrypt/include/asn.h @@ -77,8 +77,20 @@ enum DN_Tags { ASN_ORGUNIT_NAME = 0x0b /* OU */ }; +enum PBES { + PBE_MD5_DES = 0, + PBE_SHA1_DES = 1 +}; + +enum ENCRYPTION_TYPES { + DES_TYPE = 0 +}; + enum Misc_ASN { - ASN_NAME_MAX = 256, + ASN_NAME_MAX = 256, + MAX_SALT_SIZE = 64, /* MAX PKCS Salt length */ + MAX_KEY_SIZE = 64, /* MAX PKCS Key length */ + PKCS5 = 5, /* PKCS oid tag */ SHA_SIZE = 20, RSA_INTS = 8, /* RSA ints in private key */ MIN_DATE_SIZE = 13, @@ -222,6 +234,7 @@ void FreeSigners(Signer*, void*); int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32); int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32); int ToTraditional(byte* buffer, word32 length); +int ToTraditionalEnc(byte* buffer, word32 length, const char*, int); #ifndef NO_DH int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32); diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 106974bc9..cec7db28b 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -29,6 +29,8 @@ #include "ctc_sha.h" #include "ctc_md5.h" #include "error.h" +#include "pwdbased.h" +#include "des3.h" #ifdef HAVE_NTRU #include "crypto_ntru.h" @@ -67,7 +69,7 @@ enum { #define NO_TIME_H /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */ #elif defined(USER_TIME) - /* no strucutres used */ + /* no structures used */ #define NO_TIME_H /* user time, and gmtime compatible functions, there is a gmtime implementation here that WINCE uses, so really just need some ticks @@ -342,6 +344,31 @@ int GetMyVersion(const byte* input, word32* inOutIdx, int* version) } +/* Get small count integer, 32 bits or less */ +int GetShortInt(const byte* input, word32* inOutIdx, int* number) +{ + word32 idx = *inOutIdx; + word32 len; + + *number = 0; + + if (input[idx++] != ASN_INTEGER) + return ASN_PARSE_E; + + len = input[idx++]; + if (len > 4) + return ASN_PARSE_E; + + while (len--) { + *number = *number << 8 | input[idx++]; + } + + *inOutIdx = idx; + + return *number; +} + + /* May not have one, not an error */ int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version) { @@ -489,6 +516,138 @@ int ToTraditional(byte* input, word32 sz) } +/* Check To see if PKCS version algo is supported, set id if it is return 0 + < 0 on error */ +static int CheckAlgo(int version, int algo, int* id) +{ + if (version != PKCS5) + return ASN_INPUT_E; /* VERSION ERROR */ + + switch (algo) { + case 3: /* see RFC 2898 for ids */ + *id = PBE_MD5_DES; + return 0; + case 10: + *id = PBE_SHA1_DES; + return 0; + default: + return -1; + + } +} + + +/* Decrypt intput in place from parameters based on id */ +static int DecryptKey(const char* password, int passwordSz, byte* salt, + int saltSz, int iterations, int id, byte* input, int length) +{ + byte key[MAX_KEY_SIZE]; + int hashType; + int derivedLen; + int decryptionType; + + switch (id) { + case PBE_MD5_DES: + hashType = MD5; + derivedLen = 16; + decryptionType = DES_TYPE; + break; + + case PBE_SHA1_DES: + hashType = SHA; + derivedLen = 16; + decryptionType = DES_TYPE; + break; + + default: + return -1; /* unknown algo id */ + } + + PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations, + derivedLen, hashType); + + switch (decryptionType) { + case DES_TYPE: + { + Des dec; + Des_SetKey(&dec, key, key + 8, DES_DECRYPTION); + Des_CbcDecrypt(&dec, input, input, length); + break; + } + + default: + return -1; /* unknown algo id */ + } + + return 0; +} + + +/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning + of input */ +int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) +{ + word32 inOutIdx = 0, oid; + int type, algo, version, length, iterations, saltSz, id; + byte salt[MAX_SALT_SIZE]; + + if (GetSequence(input, &inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + if (GetAlgoId(input, &inOutIdx, &oid) < 0) + return ASN_PARSE_E; + + version = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */ + algo = input[inOutIdx - 1]; /* version.algo, algo id last byte */ + + if (CheckAlgo(version, algo, &id) < 0) + return ASN_INPUT_E; /* Algo ID error */ + + if (GetSequence(input, &inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &saltSz) < 0) + return ASN_PARSE_E; + + if (saltSz > MAX_SALT_SIZE) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + XMEMCPY(salt, &input[inOutIdx], saltSz); + inOutIdx += saltSz; + + if (GetShortInt(input, &inOutIdx, &iterations) < 0) + return ASN_PARSE_E; + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id, + input + inOutIdx, length) < 0) + return ASN_INPUT_E; /* decrypt failure */ + + XMEMMOVE(input, input + inOutIdx, length); + return ToTraditional(input, length); +} + + int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, word32 inSz) { @@ -823,7 +982,7 @@ static int GetKey(DecodedCert* cert) DYNAMIC_TYPE_PUBLIC_KEY); if (cert->publicKey == NULL) return MEMORY_E; - memcpy(cert->publicKey, keyBlob, keyLen); + XMEMCPY(cert->publicKey, keyBlob, keyLen); cert->pubKeyStored = 1; cert->pubKeySize = keyLen; } @@ -861,7 +1020,7 @@ static int GetKey(DecodedCert* cert) DYNAMIC_TYPE_PUBLIC_KEY); if (cert->publicKey == NULL) return MEMORY_E; - memcpy(cert->publicKey, &cert->source[cert->srcIdx], length - 1); + XMEMCPY(cert->publicKey, &cert->source[cert->srcIdx], length - 1); cert->pubKeyStored = 1; cert->pubKeySize = length - 1; diff --git a/ctaocrypt/src/ecc.c b/ctaocrypt/src/ecc.c new file mode 100644 index 000000000..9f03ed2f2 --- /dev/null +++ b/ctaocrypt/src/ecc.c @@ -0,0 +1 @@ +/* dummy ecc.c for dist */ diff --git a/ctaocrypt/src/ecc_fp.c b/ctaocrypt/src/ecc_fp.c new file mode 100644 index 000000000..c8acf9387 --- /dev/null +++ b/ctaocrypt/src/ecc_fp.c @@ -0,0 +1 @@ +/* dummy ecc_fp.c for dist */ diff --git a/include/cyassl_int.h b/include/cyassl_int.h index 39042801d..f7a79289b 100644 --- a/include/cyassl_int.h +++ b/include/cyassl_int.h @@ -255,10 +255,10 @@ enum Misc { SIZEOF_SENDER = 4, /* clnt or srvr */ FINISHED_SZ = MD5_DIGEST_SIZE + SHA_DIGEST_SIZE, MAX_RECORD_SIZE = 16384, /* 2^14, max size by standard */ - MAX_UDP_SIZE = 1400, /* don't exceed MTU */ MAX_MSG_EXTRA = 68, /* max added to msg, mac + pad */ MAX_COMP_EXTRA = 1024, /* max compression extra */ MAX_MTU = 1500, /* max expected MTU */ + MAX_UDP_SIZE = MAX_MTU - 100, /* don't exceed MTU w/ 100 byte header */ MAX_DH_SZ = 612, /* 2240 p, pub, g + 2 byte size for each */ MAX_STR_VERSION = 8, /* string rep of protocol version */ @@ -1027,10 +1027,11 @@ enum { typedef struct EncryptedInfo { - char name[NAME_SZ]; - byte iv[IV_SZ]; - word32 ivSz; - byte set; + char name[NAME_SZ]; + byte iv[IV_SZ]; + word32 ivSz; + byte set; + SSL_CTX* ctx; } EncryptedInfo; diff --git a/include/openssl/cyassl_test.h b/include/openssl/cyassl_test.h index 8e0a458cc..768281f63 100644 --- a/include/openssl/cyassl_test.h +++ b/include/openssl/cyassl_test.h @@ -99,7 +99,8 @@ const char* eccCert = "../../certs/server-ecc.pem"; const char* eccKey = "../../certs/ecc-key.pem"; const char* svrCert = "../../certs/server-cert.pem"; - const char* svrKey = "../../certs/server-key.pem"; + //const char* svrKey = "../../certs/server-key.pem"; + const char* svrKey = "../../certs/server-keyPkcs8Enc.pem"; const char* cliCert = "../../certs/client-cert.pem"; const char* cliKey = "../../certs/client-key.pem"; const char* ntruCert = "../../certs/ntru-cert.pem"; @@ -109,7 +110,8 @@ static const char* eccCert = "../certs/server-ecc.pem"; static const char* eccKey = "../certs/ecc-key.pem"; static const char* svrCert = "../certs/server-cert.pem"; - static const char* svrKey = "../certs/server-key.pem"; + //static const char* svrKey = "../certs/server-key.pem"; + static const char* svrKey = "../certs/server-keyPkcs8Enc.pem"; static const char* cliCert = "../certs/client-cert.pem"; static const char* cliKey = "../certs/client-key.pem"; static const char* ntruCert = "../certs/ntru-cert.pem"; diff --git a/src/cyassl_int.c b/src/cyassl_int.c index baf85255e..2524d9236 100644 --- a/src/cyassl_int.c +++ b/src/cyassl_int.c @@ -168,7 +168,7 @@ static INLINE void c32to48(word32 in, byte out[6]) /* convert 16 bit integer to opaque */ -static void INLINE c16toa(word16 u16, byte* c) +static INLINE void c16toa(word16 u16, byte* c) { c[0] = (u16 >> 8) & 0xff; c[1] = u16 & 0xff; @@ -1832,8 +1832,6 @@ int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx) ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); #ifdef HAVE_LIBZ - byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; - if (ssl->options.usingCompression) { dataSz = DeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp)); if (dataSz < 0) return dataSz; @@ -1976,7 +1974,9 @@ int ProcessReply(SSL* ssl) { int ret, type, readSz; word32 startIdx = 0; +#ifndef NO_CYASSL_SERVER byte b0, b1; +#endif #ifdef CYASSL_DTLS int used; #endif @@ -3895,7 +3895,8 @@ int SetCipherList(SSL_CTX* ctx, const char* list) encSigSz = EncodeSignature(encodedSig,digest,digestSz,hashType); - if (encSigSz != ret || XMEMCMP(out, encodedSig, encSigSz) != 0) + if (encSigSz != (word32)ret || XMEMCMP(out, encodedSig, + encSigSz) != 0) return VERIFY_SIGN_ERROR; } else { @@ -4900,7 +4901,7 @@ int SetCipherList(SSL_CTX* ctx, const char* list) sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType); - if (outLen == sigSz && XMEMCMP(out, encodedSig, sigSz) == 0) + if (outLen == (int)sigSz && XMEMCMP(out, encodedSig,sigSz) == 0) ret = 0; } else { diff --git a/src/cyassl_io.c b/src/cyassl_io.c index a5f5283f8..df14c3ee7 100644 --- a/src/cyassl_io.c +++ b/src/cyassl_io.c @@ -29,7 +29,7 @@ /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove automatic setting of default I/O functions EmbedSend() and EmbedReceive() - but they'll still nedd SetCallback xxx() at end of file + but they'll still need SetCallback xxx() at end of file */ #ifndef CYASSL_USER_IO diff --git a/src/ssl.c b/src/ssl.c index 32b6d30e9..d894664aa 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -210,8 +210,11 @@ int SSL_shutdown(SSL* ssl) } -int SSL_get_error(SSL* ssl, int dummy) +int SSL_get_error(SSL* ssl, int ret) { + if (ret > 0) + return SSL_ERROR_NONE; + if (ssl->error == WANT_READ) return SSL_ERROR_WANT_READ; /* convert to OpenSSL type */ else if (ssl->error == WANT_WRITE) @@ -360,7 +363,8 @@ static int AddCA(SSL_CTX* ctx, buffer der) char* headerEnd; char* footerEnd; long neededSz; - int pkcs8 = 0; + int pkcs8 = 0; + int pkcs8Enc = 0; int dynamicType; if (type == CERT_TYPE || type == CA_TYPE) { @@ -383,10 +387,16 @@ static int AddCA(SSL_CTX* ctx, buffer der) headerEnd = XSTRSTR((char*)buff, header); if (headerEnd) pkcs8 = 1; - /* - else - maybe encrypted "-----BEGIN ENCRYPTED PRIVATE KEY-----" - */ + else { + XSTRNCPY(header, "-----BEGIN ENCRYPTED PRIVATE KEY-----", + sizeof(header)); + XSTRNCPY(footer, "-----END ENCRYPTED PRIVATE KEY-----", + sizeof(footer)); + + headerEnd = XSTRSTR((char*)buff, header); + if (headerEnd) + pkcs8Enc = 1; + } } if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be ecc */ XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----", sizeof(header)); @@ -470,10 +480,17 @@ static int AddCA(SSL_CTX* ctx, buffer der) if (pkcs8) return ToTraditional(der->buffer, der->length); - /* not full support yet - if (pkcs8Enc) - return ToTraditionalEnc(der->buffer, der->length); - */ + if (pkcs8Enc) { + int passwordSz; + char password[80]; + + if (!info->ctx->passwd_cb) + return SSL_BAD_FILE; /* no callback error */ + passwordSz = info->ctx->passwd_cb(password, sizeof(password), 0, + info->ctx->userdata); + return ToTraditionalEnc(der->buffer, der->length, password, + passwordSz); + } return 0; } @@ -488,6 +505,7 @@ static int AddCA(SSL_CTX* ctx, buffer der) int eccKey = 0; info.set = 0; + info.ctx = ctx; der.buffer = 0; if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM @@ -502,9 +520,10 @@ static int AddCA(SSL_CTX* ctx, buffer der) dynamicType = DYNAMIC_TYPE_KEY; if (format == SSL_FILETYPE_PEM) { - if (PemToDer(buff, sz, type, &der, ctx->heap, &info, &eccKey) < 0) { + int ret = PemToDer(buff, sz, type, &der, ctx->heap, &info, &eccKey); + if (ret < 0) { XFREE(der.buffer, ctx->heap, dynamicType); - return SSL_BAD_FILE; + return ret; } } else { /* ASN1 (DER) or RAW (NTRU) */ @@ -660,7 +679,7 @@ static int ProcessFile(SSL_CTX* ctx, const char* fname, int format, int type) sz = XFTELL(file); XREWIND(file); - if (sz > sizeof(staticBuffer)) { + if (sz > (long)sizeof(staticBuffer)) { buffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); if (buffer == NULL) { XFCLOSE(file); @@ -744,7 +763,7 @@ int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) if (ret == 0) { if (converted.length < derSz) { - memcpy(derBuf, converted.buffer, converted.length); + XMEMCPY(derBuf, converted.buffer, converted.length); ret = converted.length; } else @@ -1574,7 +1593,7 @@ int CyaSSL_set_compression(SSL* ssl) for (i = 0; i < iovcnt; i++) send += iov[i].iov_len; - if (send > sizeof(tmp)) { + if (send > (int)sizeof(tmp)) { byte* tmp2 = (byte*) XMALLOC(send, ssl->heap, DYNAMIC_TYPE_WRITEV); if (!tmp2)