/* * Ensure the client has the private key by first decrypting the packet and * then checking the packet digests. */ static int process_cert_verify(SSL *ssl) { uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; int pkt_size = ssl->bm_index; uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; uint8_t dgst[MD5_SIZE+SHA1_SIZE]; X509_CTX *x509_ctx = ssl->x509_ctx; int ret = SSL_OK; int n; PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6); DISPLAY_RSA(ssl, x509_ctx->rsa_ctx); /* rsa_ctx->bi_ctx is not thread-safe */ SSL_CTX_LOCK(ssl->ssl_ctx->mutex); n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0); SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); if (n != SHA1_SIZE + MD5_SIZE) { ret = SSL_ERROR_INVALID_KEY; goto end_cert_vfy; } finished_digest(ssl, NULL, dgst); /* calculate the digest */ if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE)) { ret = SSL_ERROR_INVALID_KEY; } end_cert_vfy: ssl->next_state = HS_FINISHED; error: return ret; }
/* * Send a client key exchange message. */ static int send_client_key_xchg(SSL *ssl) { uint8_t *buf = ssl->bm_data; uint8_t premaster_secret[SSL_SECRET_SIZE]; int enc_secret_size = -1; buf[0] = HS_CLIENT_KEY_XCHG; buf[1] = 0; premaster_secret[0] = 0x03; /* encode the version number */ premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */ get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]); DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx); /* rsa_ctx->bi_ctx is not thread-safe */ SSL_CTX_LOCK(ssl->ssl_ctx->mutex); enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, SSL_SECRET_SIZE, &buf[6], 0); SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); buf[2] = (enc_secret_size + 2) >> 8; buf[3] = (enc_secret_size + 2) & 0xff; buf[4] = enc_secret_size >> 8; buf[5] = enc_secret_size & 0xff; generate_master_secret(ssl, premaster_secret); return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6); }
/* * Send a certificate verify message. */ static int send_cert_verify(SSL *ssl) { uint8_t *buf = ssl->bm_data; uint8_t dgst[MD5_SIZE+SHA1_SIZE]; RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; int n = 0, ret; if (rsa_ctx == NULL) return SSL_OK; DISPLAY_RSA(ssl, rsa_ctx); buf[0] = HS_CERT_VERIFY; buf[1] = 0; finished_digest(ssl, NULL, dgst); /* calculate the digest */ /* rsa_ctx->bi_ctx is not thread-safe */ if (rsa_ctx) { SSL_CTX_LOCK(ssl->ssl_ctx->mutex); n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); if (n == 0) { ret = SSL_ERROR_INVALID_KEY; goto error; } } buf[4] = n >> 8; /* add the RSA size (not officially documented) */ buf[5] = n & 0xff; n += 2; buf[2] = n >> 8; buf[3] = n & 0xff; ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4); error: return ret; }
/* * Ensure the client has the private key by first decrypting the packet and * then checking the packet digests. */ static int process_cert_verify(SSL *ssl) { uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; int pkt_size = ssl->bm_index; uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; uint8_t dgst[MD5_SIZE + SHA1_SIZE]; X509_CTX *x509_ctx = ssl->x509_ctx; int ret = SSL_OK; int offset = 6; int rsa_len; int n; DISPLAY_RSA(ssl, x509_ctx->rsa_ctx); if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2) // TLS1.2+ { // TODO: should really need to be able to handle other algorihms. An // assumption is made on RSA/SHA256 and appears to be OK. //uint8_t hash_alg = buf[4]; //uint8_t sig_alg = buf[5]; offset = 8; rsa_len = (buf[6] << 8) + buf[7]; } else { rsa_len = (buf[4] << 8) + buf[5]; } PARANOIA_CHECK(pkt_size, offset + rsa_len); /* rsa_ctx->bi_ctx is not thread-safe */ SSL_CTX_LOCK(ssl->ssl_ctx->mutex); n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[offset], dgst_buf, sizeof(dgst_buf), 0); SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2) // TLS1.2+ { if (memcmp(dgst_buf, g_asn1_sha256, sizeof(g_asn1_sha256))) { ret = SSL_ERROR_INVALID_KEY; goto error; } finished_digest(ssl, NULL, dgst); /* calculate the digest */ if (memcmp(&dgst_buf[sizeof(g_asn1_sha256)], dgst, SHA256_SIZE)) { ret = SSL_ERROR_INVALID_KEY; goto error; } } else // TLS1.0/1.1 { if (n != SHA1_SIZE + MD5_SIZE) { ret = SSL_ERROR_INVALID_KEY; goto end_cert_vfy; } finished_digest(ssl, NULL, dgst); /* calculate the digest */ if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE)) { ret = SSL_ERROR_INVALID_KEY; } } end_cert_vfy: ssl->next_state = HS_FINISHED; error: return ret; }