diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index fa2a4acab..bb7a38ef9 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -120,6 +120,7 @@ THREAD_RETURN CYASSL_API echoserver_test(void* args) ssl = SSL_new(ctx); if (ssl == NULL) err_sys("SSL_new failed"); SSL_set_fd(ssl, clientfd); + SetDH(ssl); if (SSL_accept(ssl) != SSL_SUCCESS) { printf("SSL_accept failed"); SSL_free(ssl); diff --git a/examples/server/server.c b/examples/server/server.c index f4d602e26..d088d612a 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -117,6 +117,7 @@ THREAD_RETURN CYASSL_API server_test(void* args) #endif SSL_set_fd(ssl, clientfd); + SetDH(ssl); #ifdef NON_BLOCKING tcp_set_nonblocking(&clientfd); diff --git a/include/cyassl_error.h b/include/cyassl_error.h index 02eab6908..02039bc1f 100644 --- a/include/cyassl_error.h +++ b/include/cyassl_error.h @@ -49,6 +49,7 @@ enum CyaSSL_ErrorCodes { NO_PEER_KEY = -216, /* need peer's key */ NO_PRIVATE_KEY = -217, /* need the private key */ RSA_PRIVATE_ERROR = -218, /* error during rsa priv op */ + NO_DH_PARAMS = -219, /* server missging DH params */ BUILD_MSG_ERROR = -220, /* build message failure */ BAD_HELLO = -221, /* client hello malformed */ diff --git a/include/openssl/cyassl_test.h b/include/openssl/cyassl_test.h index e413c52a2..14c2a5904 100644 --- a/include/openssl/cyassl_test.h +++ b/include/openssl/cyassl_test.h @@ -575,6 +575,32 @@ static int myVerify(int preverify, X509_STORE_CTX* store) #endif /* VERIFY_CALLBACK */ +static INLINE void SetDH(SSL* ssl) +{ + /* dh1024 p */ + static unsigned char p[] = + { + 0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3, + 0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E, + 0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59, + 0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2, + 0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD, + 0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF, + 0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02, + 0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C, + 0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7, + 0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50, + 0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B, + }; + + /* dh1024 g */ + static unsigned char g[] = + { + 0x02, + }; + + CyaSSL_SetTmpDH(ssl, p, sizeof(p), g, sizeof(g)); +} #endif /* CyaSSL_TEST_H */ diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index ba08dd443..905497467 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -625,6 +625,9 @@ int CyaSSL_get_chain_cert_pem(X509_CHAIN*, int idx, unsigned char* buffer, const unsigned char* CyaSSL_get_sessionID(const SSL_SESSION* session); int CyaSSL_X509_get_serial_number(X509*, unsigned char*, int*); +/* server CTX Diffie-Hellman parameters */ +int CyaSSL_SetTmpDH(SSL*, unsigned char* p, int pSz, unsigned char* g,int gSz); + #ifndef _WIN32 #ifndef NO_WRITEV #include diff --git a/src/cyassl_int.c b/src/cyassl_int.c index c9e6b7a8a..752be8640 100644 --- a/src/cyassl_int.c +++ b/src/cyassl_int.c @@ -2977,6 +2977,10 @@ void SetErrorString(int error, char* buffer) XSTRNCPY(buffer, "need the private key", max); break; + case NO_DH_PARAMS : + XSTRNCPY(buffer, "server missing DH params", max); + break; + case RSA_PRIVATE_ERROR : XSTRNCPY(buffer, "error during rsa priv op", max); break; @@ -4610,6 +4614,7 @@ int SetCipherList(SSL_CTX* ctx, const char* list) FreeRsaKey(&rsaKey); ret = ecc_sign_hash(&hash[MD5_DIGEST_SIZE], SHA_DIGEST_SIZE, output + idx, &sz, &ssl->rng, &dsaKey); + if (ret < 0) return ret; } } @@ -4629,6 +4634,194 @@ int SetCipherList(SSL_CTX* ctx, const char* list) } #endif /* HAVE_ECC */ + #ifdef OPENSSL_EXTRA + if (ssl->specs.kea == diffie_hellman_kea) { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + word32 sigSz, i = 0; + word32 preSigSz, preSigIdx; + RsaKey rsaKey; + DhKey dhKey; + + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL) + return NO_DH_PARAMS; + + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Pub.buffer == NULL) + return MEMORY_E; + } + + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Priv.buffer == NULL) + return MEMORY_E; + } + + InitDhKey(&dhKey); + ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret == 0) + ret = DhGenerateKeyPair(&dhKey, &ssl->rng, + ssl->buffers.serverDH_Priv.buffer, + &ssl->buffers.serverDH_Priv.length, + ssl->buffers.serverDH_Pub.buffer, + &ssl->buffers.serverDH_Pub.length); + FreeDhKey(&dhKey); + + if (ret == 0) { + length = LENGTH_SZ * 3; /* p, g, pub */ + length += ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + preSigIdx = idx; + preSigSz = length; + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key.buffer) + return NO_PRIVATE_KEY; + + InitRsaKey(&rsaKey, ssl->heap); + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, &rsaKey, + ssl->buffers.key.length); + if (ret == 0) { + sigSz = RsaEncryptSize(&rsaKey); + length += sigSz; + } + } + if (ret != 0) { + FreeRsaKey(&rsaKey); + return ret; + } + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) { + FreeRsaKey(&rsaKey); + return ret; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + idx += ssl->buffers.serverDH_Pub.length; + + /* Add signature */ + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = sha_mac; + output[idx++] = ssl->specs.sig_algo; + } + /* size */ + c16toa(sigSz, output + idx); + idx += LENGTH_SZ; + + /* do signature */ + { + Md5 md5; + Sha sha; + byte hash[FINISHED_SZ]; + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN); + Md5Update(&md5, output + preSigIdx, preSigSz); + Md5Final(&md5, hash); + + /* sha */ + InitSha(&sha); + ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN); + ShaUpdate(&sha, output + preSigIdx, preSigSz); + ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); + + if (ssl->specs.sig_algo == rsa_sa_algo) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest; + int hashType; + int digestSz; + + /* sha1 for now */ + digest = &hash[MD5_DIGEST_SIZE]; + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + + signSz = EncodeSignature(encodedSig, digest, digestSz, + hashType); + signBuffer = encodedSig; + } + ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz, + &rsaKey, &ssl->rng); + FreeRsaKey(&rsaKey); + if (ret > 0) + ret = 0; /* reset on success */ + else + return ret; + } + } + + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /* OPENSSL_EXTRA */ + return ret; } @@ -5182,6 +5375,33 @@ int SetCipherList(SSL_CTX* ctx, const char* list) ssl->arrays.preMasterSz = size; ret = MakeMasterSecret(ssl); #endif /* HAVE_ECC */ +#ifdef OPENSSL_EXTRA + } else if (ssl->specs.kea == diffie_hellman_kea) { + byte* clientPub; + word16 clientPubSz; + DhKey dhKey; + + ato16(&input[*inOutIdx], &clientPubSz); + *inOutIdx += LENGTH_SZ; + + clientPub = &input[*inOutIdx]; + *inOutIdx += clientPubSz; + + InitDhKey(&dhKey); + ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + if (ret == 0) + ret = DhAgree(&dhKey, ssl->arrays.preMasterSecret, + &ssl->arrays.preMasterSz, + ssl->buffers.serverDH_Priv.buffer, + ssl->buffers.serverDH_Priv.length, + clientPub, clientPubSz); + FreeDhKey(&dhKey); + if (ret == 0) + ret = MakeMasterSecret(ssl); +#endif /* OPENSSL_EXTRA */ } if (ret == 0) { diff --git a/src/ssl.c b/src/ssl.c index 008b071ed..06bebdea8 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -149,6 +149,50 @@ int CyaSSL_negotiate(SSL* ssl) } +/* server CTX Diffie-Hellman parameters */ +int CyaSSL_SetTmpDH(SSL* ssl, unsigned char* p,int pSz,unsigned char* g,int gSz) +{ + byte havePSK = 0; + + if (ssl == NULL || p == NULL || g == NULL) return -1; + + if (ssl->options.side != SERVER_END) + return SIDE_ERROR; + + if (ssl->buffers.serverDH_P.buffer) + XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_G.buffer) + XFREE(ssl->buffers.serverDH_G.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); + + ssl->buffers.serverDH_P.buffer = (byte*)XMALLOC(pSz, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_P.buffer == NULL) + return MEMORY_E; + + ssl->buffers.serverDH_G.buffer = (byte*)XMALLOC(gSz, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_G.buffer == NULL) { + XFREE(ssl->buffers.serverDH_P.buffer, ssl->ctx->heap, DYNAMIC_TYPE_DH); + return MEMORY_E; + } + + ssl->buffers.serverDH_P.length = pSz; + ssl->buffers.serverDH_G.length = gSz; + + XMEMCPY(ssl->buffers.serverDH_P.buffer, p, pSz); + XMEMCPY(ssl->buffers.serverDH_G.buffer, g, gSz); + + ssl->options.haveDH = 1; + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, + havePSK, ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + return 0; +} + + int SSL_write(SSL* ssl, const void* buffer, int sz) { int ret;