int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, const EVP_PKEY *privkey) { if (EVP_PKEY_is_opaque(privkey)) { /* We cannot check an opaque private key and have to trust that it * matches. */ return 1; } int ret = 0; switch (EVP_PKEY_cmp(pubkey, privkey)) { case 1: ret = 1; break; case 0: OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); break; case -1: OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); break; case -2: OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); default: assert(0); break; } return ret; }
static int ssl_set_cert(CERT *c, X509 *x) { EVP_PKEY *pkey = X509_get_pubkey(x); if (pkey == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_X509_LIB); return 0; } if (!is_key_type_supported(pkey->type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); EVP_PKEY_free(pkey); return 0; } if (c->privatekey != NULL) { /* Sanity-check that the private key and the certificate match, unless the * key is opaque (in case of, say, a smartcard). */ if (!EVP_PKEY_is_opaque(c->privatekey) && !X509_check_private_key(x, c->privatekey)) { /* don't fail for a cert/key mismatch, just free current private key * (when switching to a different cert & key, first this function should * be used, then ssl_set_pkey */ EVP_PKEY_free(c->privatekey); c->privatekey = NULL; /* clear error queue */ ERR_clear_error(); } } EVP_PKEY_free(pkey); X509_free(c->x509); c->x509 = X509_up_ref(x); return 1; }
static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) { if (!is_key_type_supported(pkey->type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); return 0; } if (cert->chain != NULL && sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL && /* Sanity-check that the private key and the certificate match, unless * the key is opaque (in case of, say, a smartcard). */ !EVP_PKEY_is_opaque(pkey) && !ssl_cert_check_private_key(cert, pkey)) { return 0; } EVP_PKEY_free(cert->privatekey); EVP_PKEY_up_ref(pkey); cert->privatekey = pkey; return 1; }
static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { if (!is_key_type_supported(pkey->type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); return 0; } if (c->x509 != NULL) { /* Sanity-check that the private key and the certificate match, unless the * key is opaque (in case of, say, a smartcard). */ if (!EVP_PKEY_is_opaque(pkey) && !X509_check_private_key(c->x509, pkey)) { X509_free(c->x509); c->x509 = NULL; return 0; } } EVP_PKEY_free(c->privatekey); c->privatekey = EVP_PKEY_up_ref(pkey); return 1; }
static int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { CBS cert_cbs; CRYPTO_BUFFER_init_CBS(buffer, &cert_cbs); EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); if (pubkey == NULL) { return 0; } if (!is_key_type_supported(pubkey->type)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); EVP_PKEY_free(pubkey); return 0; } /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA * certificates, so sanity-check the key usage extension. */ if (pubkey->type == EVP_PKEY_EC && !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); EVP_PKEY_free(pubkey); return 0; } if (cert->privatekey != NULL) { /* Sanity-check that the private key and the certificate match, unless the * key is opaque (in case of, say, a smartcard). */ if (!EVP_PKEY_is_opaque(cert->privatekey) && !ssl_compare_public_and_private_key(pubkey, cert->privatekey)) { /* don't fail for a cert/key mismatch, just free current private key * (when switching to a different cert & key, first this function should * be used, then ssl_set_pkey */ EVP_PKEY_free(cert->privatekey); cert->privatekey = NULL; /* clear error queue */ ERR_clear_error(); } } EVP_PKEY_free(pubkey); ssl_cert_flush_cached_x509_leaf(cert); if (cert->chain != NULL) { CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0)); sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer); CRYPTO_BUFFER_up_ref(buffer); return 1; } cert->chain = sk_CRYPTO_BUFFER_new_null(); if (cert->chain == NULL) { return 0; } if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { sk_CRYPTO_BUFFER_free(cert->chain); cert->chain = NULL; return 0; } CRYPTO_BUFFER_up_ref(buffer); return 1; }