]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - ssl/ssl_lib.c
RFC7250 (RPK) support
[thirdparty/openssl.git] / ssl / ssl_lib.c
index 83510b367a7c9cdb1b1acb238923b8223c215628..efd89cf461a79649ac13d1429c7dab1c9aa36913 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
  * Copyright 2005 Nokia. All rights reserved.
  *
@@ -883,6 +883,20 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method)
 #ifndef OPENSSL_NO_COMP_ALG
     memcpy(s->cert_comp_prefs, ctx->cert_comp_prefs, sizeof(s->cert_comp_prefs));
 #endif
+    if (ctx->client_cert_type != NULL) {
+        s->client_cert_type = OPENSSL_memdup(ctx->client_cert_type,
+                                             ctx->client_cert_type_len);
+        if (s->client_cert_type == NULL)
+            goto sslerr;
+        s->client_cert_type_len = ctx->client_cert_type_len;
+    }
+    if (ctx->server_cert_type != NULL) {
+        s->server_cert_type = OPENSSL_memdup(ctx->server_cert_type,
+                                             ctx->server_cert_type_len);
+        if (s->server_cert_type == NULL)
+            goto sslerr;
+        s->server_cert_type_len = ctx->server_cert_type_len;
+    }
 
 #ifndef OPENSSL_NO_CT
     if (!SSL_set_ct_validation_callback(ssl, ctx->ct_validation_callback,
@@ -1408,6 +1422,9 @@ void ossl_ssl_connection_free(SSL *ssl)
     sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
     sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
 
+    OPENSSL_free(s->client_cert_type);
+    OPENSSL_free(s->server_cert_type);
+
     OSSL_STACK_OF_X509_free(s->verified_chain);
 
     if (ssl->method != NULL)
@@ -4099,6 +4116,9 @@ void SSL_CTX_free(SSL_CTX *a)
     OPENSSL_free(a->sigalg_lookup_cache);
     OPENSSL_free(a->tls12_sigalgs);
 
+    OPENSSL_free(a->client_cert_type);
+    OPENSSL_free(a->server_cert_type);
+
     CRYPTO_THREAD_lock_free(a->lock);
 #ifdef TSAN_REQUIRES_LOCKING
     CRYPTO_THREAD_lock_free(a->tsan_lock);
@@ -4266,6 +4286,24 @@ void ssl_set_masks(SSL_CONNECTION *s)
 
     mask_a |= SSL_aNULL;
 
+    /*
+     * You can do anything with an RPK key, since there's no cert to restrict it
+     * But we need to check for private keys
+     */
+    if (pvalid[SSL_PKEY_RSA] & CERT_PKEY_RPK) {
+        mask_a |= SSL_aRSA;
+        mask_k |= SSL_kRSA;
+    }
+    if (pvalid[SSL_PKEY_ECC] & CERT_PKEY_RPK)
+        mask_a |= SSL_aECDSA;
+    if (TLS1_get_version(&s->ssl) == TLS1_2_VERSION) {
+        if (pvalid[SSL_PKEY_RSA_PSS_SIGN] & CERT_PKEY_RPK)
+            mask_a |= SSL_aRSA;
+        if (pvalid[SSL_PKEY_ED25519] & CERT_PKEY_RPK
+                || pvalid[SSL_PKEY_ED448] & CERT_PKEY_RPK)
+            mask_a |= SSL_aECDSA;
+    }
+
     /*
      * An ECC certificate may be usable for ECDH and/or ECDSA cipher suites
      * depending on the key usage extension.
@@ -7254,3 +7292,175 @@ int SSL_stream_conclude(SSL *ssl, uint64_t flags)
     return 0;
 #endif
 }
+
+int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk)
+{
+    unsigned char *data = NULL;
+    SSL_DANE *dane = SSL_get0_dane(s);
+    int ret;
+
+    if (dane == NULL || dane->dctx == NULL)
+        return 0;
+    if ((ret = i2d_PUBKEY(rpk, &data)) <= 0)
+        return 0;
+
+    ret = SSL_dane_tlsa_add(s, DANETLS_USAGE_DANE_EE,
+                            DANETLS_SELECTOR_SPKI,
+                            DANETLS_MATCHING_FULL,
+                            data, (size_t)ret) > 0;
+    OPENSSL_free(data);
+    return ret;
+}
+
+EVP_PKEY *SSL_get0_peer_rpk(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL || sc->session == NULL)
+        return NULL;
+    return sc->session->peer_rpk;
+}
+
+int SSL_get_negotiated_client_cert_type(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->ext.client_cert_type;
+}
+
+int SSL_get_negotiated_server_cert_type(const SSL *s)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    if (sc == NULL)
+        return 0;
+
+    return sc->ext.server_cert_type;
+}
+
+static int validate_cert_type(const unsigned char *val, size_t len)
+{
+    size_t i;
+    int saw_rpk = 0;
+    int saw_x509 = 0;
+
+    if (val == NULL && len == 0)
+        return 1;
+
+    if (val == NULL || len == 0)
+        return 0;
+
+    for (i = 0; i < len; i++) {
+        switch (val[i]) {
+        case TLSEXT_cert_type_rpk:
+            if (saw_rpk)
+                return 0;
+            saw_rpk = 1;
+            break;
+        case TLSEXT_cert_type_x509:
+            if (saw_x509)
+                return 0;
+            saw_x509 = 1;
+            break;
+        case TLSEXT_cert_type_pgp:
+        case TLSEXT_cert_type_1609dot2:
+        default:
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int set_cert_type(unsigned char **cert_type,
+                         size_t *cert_type_len,
+                         const unsigned char *val,
+                         size_t len)
+{
+    unsigned char *tmp = NULL;
+
+    if (!validate_cert_type(val, len))
+        return 0;
+
+    if (val != NULL && (tmp = OPENSSL_memdup(val, len)) == NULL)
+        return 0;
+
+    OPENSSL_free(*cert_type);
+    *cert_type = tmp;
+    *cert_type_len = len;
+    return 1;
+}
+
+int SSL_set1_client_cert_type(SSL *s, const unsigned char *val, size_t len)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    return set_cert_type(&sc->client_cert_type, &sc->client_cert_type_len,
+                         val, len);
+}
+
+int SSL_set1_server_cert_type(SSL *s, const unsigned char *val, size_t len)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+
+    return set_cert_type(&sc->server_cert_type, &sc->server_cert_type_len,
+                         val, len);
+}
+
+int SSL_CTX_set1_client_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len)
+{
+    return set_cert_type(&ctx->client_cert_type, &ctx->client_cert_type_len,
+                         val, len);
+}
+
+int SSL_CTX_set1_server_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len)
+{
+    return set_cert_type(&ctx->server_cert_type, &ctx->server_cert_type_len,
+                         val, len);
+}
+
+int SSL_get0_client_cert_type(const SSL *s, unsigned char **t, size_t *len)
+{
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = sc->client_cert_type;
+    *len = sc->client_cert_type_len;
+    return 1;
+}
+
+int SSL_get0_server_cert_type(const SSL *s, unsigned char **t, size_t *len)
+{
+    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = sc->server_cert_type;
+    *len = sc->server_cert_type_len;
+    return 1;
+}
+
+int SSL_CTX_get0_client_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len)
+{
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = ctx->client_cert_type;
+    *len = ctx->client_cert_type_len;
+    return 1;
+}
+
+int SSL_CTX_get0_server_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len)
+{
+    if (t == NULL || len == NULL)
+        return 0;
+
+    *t = ctx->server_cert_type;
+    *len = ctx->server_cert_type_len;
+    return 1;
+}