RFC7250 (RPK) support
authorTodd Short <tshort@akamai.com>
Wed, 27 Jan 2021 19:23:33 +0000 (14:23 -0500)
committerTodd Short <todd.short@me.com>
Tue, 28 Mar 2023 17:49:54 +0000 (13:49 -0400)
Add support for the RFC7250 certificate-type extensions.
Alows the use of only private keys for connection (i.e. certs not needed).

Add APIs
Add unit tests
Add documentation
Add s_client/s_server support

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18185)

49 files changed:
CHANGES.md
NEWS.md
apps/lib/s_cb.c
apps/s_client.c
apps/s_server.c
crypto/err/openssl.txt
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
doc/build.info
doc/man1/openssl-s_client.pod.in
doc/man1/openssl-s_server.pod.in
doc/man3/SSL_CTX_dane_enable.pod
doc/man3/SSL_get0_peer_rpk.pod [new file with mode: 0644]
doc/man3/SSL_set1_server_cert_type.pod [new file with mode: 0644]
doc/man3/X509_STORE_CTX_get_error.pod
doc/man3/X509_STORE_CTX_new.pod
doc/man3/X509_verify.pod
doc/man3/X509_verify_cert.pod
doc/man3/d2i_SSL_SESSION.pod
include/crypto/x509.h
include/openssl/ssl.h.in
include/openssl/sslerr.h
include/openssl/tls1.h
include/openssl/x509_vfy.h.in
ssl/ssl_asn1.c
ssl/ssl_cert.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_local.h
ssl/ssl_sess.c
ssl/statem/extensions.c
ssl/statem/extensions_clnt.c
ssl/statem/extensions_cust.c
ssl/statem/extensions_srvr.c
ssl/statem/statem_clnt.c
ssl/statem/statem_lib.c
ssl/statem/statem_local.h
ssl/statem/statem_srvr.c
ssl/t1_lib.c
ssl/t1_trce.c
test/build.info
test/ext_internal_test.c
test/recipes/70-test_certtypeext.t [new file with mode: 0644]
test/recipes/90-test_rpk.t [new file with mode: 0644]
test/rpktest.c [new file with mode: 0644]
test/sslapitest.c
util/libcrypto.num
util/libssl.num
util/perl/TLSProxy/Message.pm

index 253f2fd8236b73df9636dd57abdf2752016e880f..452e5d0e7490cdd7087c32f39f8d544921348ab2 100644 (file)
@@ -25,6 +25,14 @@ OpenSSL 3.2
 
 ### Changes between 3.1 and 3.2 [xx XXX xxxx]
 
+ * Add Raw Public Key (RFC7250) support. Authentication is supported
+   by matching keys against either local policy (TLSA records synthesised
+   from the expected keys) or DANE (TLSA records obtained by the
+   application from DNS). TLSA records will also match the same key in
+   the server certificate, should RPK use not happen to be negotiated.
+
+   *Todd Short*
+
  * Added EC_GROUP_to_params which creates an OSSL_PARAM array
    from a given EC_GROUP.
 
diff --git a/NEWS.md b/NEWS.md
index ef077a543747bd559a19de6fb0c586208085f664..5f154d1e6e1a29ad1ee8a624093643061cf054af 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -22,6 +22,7 @@ OpenSSL 3.2
 
 ### Major changes between OpenSSL 3.1 and OpenSSL 3.2 [under development]
 
+  * Add Raw Public Key (RFC7250) support.
   * Added support for certificate compression (RFC8879), including
     library support for Brotli and Zstandard compression.
   * Subject or issuer names in X.509 objects are now displayed as UTF-8 strings
index 04464bec03e12eece8a1a8e916d311f539399936..dcfea55dc5696e1fe80fdc1be7a83708939600a0 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.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -673,6 +673,8 @@ static STRINT_PAIR tlsext_types[] = {
     {"session ticket", TLSEXT_TYPE_session_ticket},
     {"renegotiation info", TLSEXT_TYPE_renegotiate},
     {"signed certificate timestamps", TLSEXT_TYPE_signed_certificate_timestamp},
+    {"client cert type", TLSEXT_TYPE_client_cert_type},
+    {"server cert type", TLSEXT_TYPE_server_cert_type},
     {"TLS padding", TLSEXT_TYPE_padding},
 #ifdef TLSEXT_TYPE_next_proto_neg
     {"next protocol", TLSEXT_TYPE_next_proto_neg},
@@ -1171,7 +1173,7 @@ static char *hexencode(const unsigned char *data, size_t len)
 void print_verify_detail(SSL *s, BIO *bio)
 {
     int mdpth;
-    EVP_PKEY *mspki;
+    EVP_PKEY *mspki = NULL;
     long verify_err = SSL_get_verify_result(s);
 
     if (verify_err == X509_V_OK) {
@@ -1206,12 +1208,15 @@ void print_verify_detail(SSL *s, BIO *bio)
             hexdata = hexencode(data + dlen - TLSA_TAIL_SIZE, TLSA_TAIL_SIZE);
         else
             hexdata = hexencode(data, dlen);
-        BIO_printf(bio, "DANE TLSA %d %d %d %s%s %s at depth %d\n",
+        BIO_printf(bio, "DANE TLSA %d %d %d %s%s ",
                    usage, selector, mtype,
-                   (dlen > TLSA_TAIL_SIZE) ? "..." : "", hexdata,
-                   (mspki != NULL) ? "signed the certificate" :
-                   mdpth ? "matched TA certificate" : "matched EE certificate",
-                   mdpth);
+                   (dlen > TLSA_TAIL_SIZE) ? "..." : "", hexdata);
+        if (SSL_get0_peer_rpk(s) == NULL)
+            BIO_printf(bio, "%s certificate at depth %d\n",
+                       (mspki != NULL) ? "signed the peer" :
+                       mdpth ? "matched the TA" : "matched the EE", mdpth);
+        else
+            BIO_printf(bio, "matched the peer raw public key\n");
         OPENSSL_free(hexdata);
     }
 }
@@ -1219,17 +1224,16 @@ void print_verify_detail(SSL *s, BIO *bio)
 void print_ssl_summary(SSL *s)
 {
     const SSL_CIPHER *c;
-    X509 *peer;
+    X509 *peer = SSL_get0_peer_certificate(s);
+    EVP_PKEY *peer_rpk = SSL_get0_peer_rpk(s);
+    int nid;
 
     BIO_printf(bio_err, "Protocol version: %s\n", SSL_get_version(s));
     print_raw_cipherlist(s);
     c = SSL_get_current_cipher(s);
     BIO_printf(bio_err, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c));
     do_print_sigalgs(bio_err, s, 0);
-    peer = SSL_get0_peer_certificate(s);
     if (peer != NULL) {
-        int nid;
-
         BIO_puts(bio_err, "Peer certificate: ");
         X509_NAME_print_ex(bio_err, X509_get_subject_name(peer),
                            0, get_nameopt());
@@ -1239,8 +1243,13 @@ void print_ssl_summary(SSL *s)
         if (SSL_get_peer_signature_type_nid(s, &nid))
             BIO_printf(bio_err, "Signature type: %s\n", get_sigtype(nid));
         print_verify_detail(s, bio_err);
+    } else if (peer_rpk != NULL) {
+        BIO_printf(bio_err, "Peer used raw public key\n");
+        if (SSL_get_peer_signature_type_nid(s, &nid))
+            BIO_printf(bio_err, "Signature type: %s\n", get_sigtype(nid));
+        print_verify_detail(s, bio_err);
     } else {
-        BIO_puts(bio_err, "No peer certificate\n");
+        BIO_puts(bio_err, "No peer certificate or raw public key\n");
     }
 #ifndef OPENSSL_NO_EC
     ssl_print_point_formats(bio_err, s);
@@ -1595,4 +1604,3 @@ int progress_cb(EVP_PKEY_CTX *ctx)
     (void)BIO_flush(b);
     return 1;
 }
-
index 9942893bd35eb2b8ffff193240bedf383f049e7f..408be290f39e1854f208076f7b5aaf48044da121 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 2005 Nokia. All rights reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
@@ -75,6 +75,9 @@ static int ocsp_resp_cb(SSL *s, void *arg);
 static int ldap_ExtendedResponse_parse(const char *buf, long rem);
 static int is_dNS_name(const char *host);
 
+static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
+static int enable_server_rpk = 0;
+
 static int saved_errno;
 
 static void save_errno(void)
@@ -468,6 +471,8 @@ typedef enum OPTION_choice {
 #endif
     OPT_DANE_TLSA_RRDATA, OPT_DANE_EE_NO_NAME,
     OPT_ENABLE_PHA,
+    OPT_ENABLE_SERVER_RPK,
+    OPT_ENABLE_CLIENT_RPK,
     OPT_SCTP_LABEL_BUG,
     OPT_KTLS,
     OPT_R_ENUM, OPT_PROV_ENUM
@@ -658,6 +663,8 @@ const OPTIONS s_client_options[] = {
 #endif
     {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"},
     {"enable_pha", OPT_ENABLE_PHA, '-', "Enable post-handshake-authentication"},
+    {"enable_server_rpk", OPT_ENABLE_SERVER_RPK, '-', "Enable raw public keys (RFC7250) from the server"},
+    {"enable_client_rpk", OPT_ENABLE_CLIENT_RPK, '-', "Enable raw public keys (RFC7250) from the client"},
 #ifndef OPENSSL_NO_SRTP
     {"use_srtp", OPT_USE_SRTP, 's',
      "Offer SRTP key management with a colon-separated profile list"},
@@ -896,6 +903,7 @@ int s_client_main(int argc, char **argv)
 #endif
     char *psksessf = NULL;
     int enable_pha = 0;
+    int enable_client_rpk = 0;
 #ifndef OPENSSL_NO_SCTP
     int sctp_label_bug = 0;
 #endif
@@ -1489,6 +1497,12 @@ int s_client_main(int argc, char **argv)
             enable_ktls = 1;
 #endif
             break;
+        case OPT_ENABLE_SERVER_RPK:
+            enable_server_rpk = 1;
+            break;
+        case OPT_ENABLE_CLIENT_RPK:
+            enable_client_rpk = 1;
+            break;
         }
     }
 
@@ -1980,6 +1994,18 @@ int s_client_main(int argc, char **argv)
     if (enable_pha)
         SSL_set_post_handshake_auth(con, 1);
 
+    if (enable_client_rpk)
+        if (!SSL_set1_client_cert_type(con, cert_type_rpk, sizeof(cert_type_rpk))) {
+            BIO_printf(bio_err, "Error setting client certificate types\n");
+            goto end;
+        }
+    if (enable_server_rpk) {
+        if (!SSL_set1_server_cert_type(con, cert_type_rpk, sizeof(cert_type_rpk))) {
+            BIO_printf(bio_err, "Error setting server certificate types\n");
+            goto end;
+        }
+    }
+
     if (sess_in != NULL) {
         SSL_SESSION *sess;
         BIO *stmp = BIO_new_file(sess_in, "r");
@@ -3254,6 +3280,23 @@ static void print_stuff(BIO *bio, SSL *s, int full)
         } else {
             BIO_printf(bio, "no peer certificate available\n");
         }
+
+        /* Only display RPK information if configured */
+        if (SSL_get_negotiated_client_cert_type(s) == TLSEXT_cert_type_rpk)
+            BIO_printf(bio, "Client-to-server raw public key negotiated\n");
+        if (SSL_get_negotiated_server_cert_type(s) == TLSEXT_cert_type_rpk)
+            BIO_printf(bio, "Server-to-client raw public key negotiated\n");
+        if (enable_server_rpk) {
+            EVP_PKEY *peer_rpk = SSL_get0_peer_rpk(s);
+
+            if (peer_rpk != NULL) {
+                BIO_printf(bio, "Server raw public key\n");
+                EVP_PKEY_print_public(bio, peer_rpk, 2, NULL);
+            } else {
+                BIO_printf(bio, "no peer rpk available\n");
+            }
+        }
+
         print_ca_names(bio, s);
 
         ssl_print_sigalgs(bio, s);
index e822bcc0905453698a4b475dc97c68e1c81df1be..7c18f9ad65966e53aebb9a7818ea14f8edbbb5f4 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.
  *
@@ -100,6 +100,9 @@ static int use_zc_sendfile = 0;
 
 static const char *session_id_prefix = NULL;
 
+static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
+static int enable_client_rpk = 0;
+
 #ifndef OPENSSL_NO_DTLS
 static int enable_timeouts = 0;
 static long socket_mtu;
@@ -720,6 +723,8 @@ typedef enum OPTION_choice {
     OPT_HTTP_SERVER_BINMODE, OPT_NOCANAMES, OPT_IGNORE_UNEXPECTED_EOF, OPT_KTLS,
     OPT_USE_ZC_SENDFILE,
     OPT_TFO, OPT_CERT_COMP,
+    OPT_ENABLE_SERVER_RPK,
+    OPT_ENABLE_CLIENT_RPK,
     OPT_R_ENUM,
     OPT_S_ENUM,
     OPT_V_ENUM,
@@ -971,7 +976,8 @@ const OPTIONS s_server_options[] = {
     {"sendfile", OPT_SENDFILE, '-', "Use sendfile to response file with -WWW"},
     {"zerocopy_sendfile", OPT_USE_ZC_SENDFILE, '-', "Use zerocopy mode of KTLS sendfile"},
 #endif
-
+    {"enable_server_rpk", OPT_ENABLE_SERVER_RPK, '-', "Enable raw public keys (RFC7250) from the server"},
+    {"enable_client_rpk", OPT_ENABLE_CLIENT_RPK, '-', "Enable raw public keys (RFC7250) from the client"},
     OPT_R_OPTIONS,
     OPT_S_OPTIONS,
     OPT_V_OPTIONS,
@@ -1069,6 +1075,7 @@ int s_server_main(int argc, char *argv[])
 #endif
     int tfo = 0;
     int cert_comp = 0;
+    int enable_server_rpk = 0;
 
     /* Init of few remaining global variables */
     local_argc = argc;
@@ -1675,6 +1682,12 @@ int s_server_main(int argc, char *argv[])
         case OPT_CERT_COMP:
             cert_comp = 1;
             break;
+        case OPT_ENABLE_SERVER_RPK:
+            enable_server_rpk = 1;
+            break;
+        case OPT_ENABLE_CLIENT_RPK:
+            enable_client_rpk = 1;
+            break;
         }
     }
 
@@ -2274,6 +2287,16 @@ int s_server_main(int argc, char *argv[])
         if (ctx2 != NULL && !SSL_CTX_compress_certs(ctx2, 0))
             BIO_printf(bio_s_out, "Error compressing certs on ctx2\n");
     }
+    if (enable_server_rpk)
+        if (!SSL_CTX_set1_server_cert_type(ctx, cert_type_rpk, sizeof(cert_type_rpk))) {
+            BIO_printf(bio_s_out, "Error setting server certificate types\n");
+            goto end;
+        }
+    if (enable_client_rpk)
+        if (!SSL_CTX_set1_client_cert_type(ctx, cert_type_rpk, sizeof(cert_type_rpk))) {
+            BIO_printf(bio_s_out, "Error setting server certificate types\n");
+            goto end;
+        }
 
     if (rev)
         server_cb = rev_body;
@@ -3025,6 +3048,19 @@ static void print_connection_info(SSL *con)
         dump_cert_text(bio_s_out, peer);
         peer = NULL;
     }
+    /* Only display RPK information if configured */
+    if (SSL_get_negotiated_server_cert_type(con) == TLSEXT_cert_type_rpk)
+        BIO_printf(bio_s_out, "Server-to-client raw public key negotiated\n");
+    if (SSL_get_negotiated_client_cert_type(con) == TLSEXT_cert_type_rpk)
+        BIO_printf(bio_s_out, "Client-to-server raw public key negotiated\n");
+    if (enable_client_rpk) {
+        EVP_PKEY *client_rpk = SSL_get0_peer_rpk(con);
+
+        if (client_rpk != NULL) {
+            BIO_printf(bio_s_out, "Client raw public key\n");
+            EVP_PKEY_print_public(bio_s_out, client_rpk, 2, NULL);
+        }
+    }
 
     if (SSL_get_shared_ciphers(con, buf, sizeof(buf)) != NULL)
         BIO_printf(bio_s_out, "Shared ciphers:%s\n", buf);
@@ -3792,7 +3828,8 @@ static SSL_SESSION *get_session(SSL *ssl, const unsigned char *id, int idlen,
         if (idlen == (int)sess->idlen && !memcmp(sess->id, id, idlen)) {
             const unsigned char *p = sess->der;
             BIO_printf(bio_err, "Lookup session: cache hit\n");
-            return d2i_SSL_SESSION(NULL, &p, sess->derlen);
+            return d2i_SSL_SESSION_ex(NULL, &p, sess->derlen, app_get0_libctx(),
+                                      app_get0_propq());
         }
     }
     BIO_printf(bio_err, "Lookup session: cache miss\n");
index 3f7f4bf109267346b010b7c2212348cbfb2a142a..330aba84c7b162e2b4f75b458cdf7a3b29f02832 100644 (file)
@@ -1280,6 +1280,7 @@ SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT:272:\
        attempt to reuse session in different context
 SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE:158:\
        at least (D)TLS 1.2 needed in Suite B mode
+SSL_R_BAD_CERTIFICATE:348:bad certificate
 SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec
 SSL_R_BAD_CIPHER:186:bad cipher
 SSL_R_BAD_COMPRESSION_ALGORITHM:326:bad compression algorithm
@@ -1369,6 +1370,7 @@ SSL_R_DUPLICATE_COMPRESSION_ID:309:duplicate compression id
 SSL_R_ECC_CERT_NOT_FOR_SIGNING:318:ecc cert not for signing
 SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE:374:ecdh required for suiteb mode
 SSL_R_EE_KEY_TOO_SMALL:399:ee key too small
+SSL_R_EMPTY_RAW_PUBLIC_KEY:349:empty raw public key
 SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST:354:empty srtp protection profile list
 SSL_R_ENCRYPTED_LENGTH_TOO_LONG:150:encrypted length too long
 SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST:151:error in received cipher list
@@ -1404,6 +1406,7 @@ SSL_R_INVALID_CT_VALIDATION_TYPE:212:invalid ct validation type
 SSL_R_INVALID_KEY_UPDATE_TYPE:120:invalid key update type
 SSL_R_INVALID_MAX_EARLY_DATA:174:invalid max early data
 SSL_R_INVALID_NULL_CMD_NAME:385:invalid null cmd name
+SSL_R_INVALID_RAW_PUBLIC_KEY:350:invalid raw public key
 SSL_R_INVALID_RECORD:317:invalid record
 SSL_R_INVALID_SEQUENCE_NUMBER:402:invalid sequence number
 SSL_R_INVALID_SERVERINFO_DATA:388:invalid serverinfo data
@@ -1612,6 +1615,7 @@ SSL_R_VERSION_TOO_LOW:396:version too low
 SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type
 SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned
 SSL_R_WRONG_CURVE:378:wrong curve
+SSL_R_WRONG_RPK_TYPE:351:wrong rpk type
 SSL_R_WRONG_SIGNATURE_LENGTH:264:wrong signature length
 SSL_R_WRONG_SIGNATURE_SIZE:265:wrong signature size
 SSL_R_WRONG_SIGNATURE_TYPE:370:wrong signature type
index 8fb38cf3e98b7c12b1dabe885b3800792090f872..e825ce2db8b987be0a264c6ba275f5b5111d5ead 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -212,6 +212,8 @@ const char *X509_verify_cert_error_string(long n)
         return "Using cert extension requires at least X509v3";
     case X509_V_ERR_EC_KEY_EXPLICIT_PARAMS:
         return "Certificate public key has explicit ECC parameters";
+    case X509_V_ERR_RPK_UNTRUSTED:
+        return "Raw public key untrusted, no trusted keys configured";
 
         /*
          * Entries must be kept consistent with include/openssl/x509_vfy.h.in
index 951beafb3ee85fa990f5489baf062552a1a18bad..cc02c1ccc474476d55f6429addb113696fab958a 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.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #define CRL_SCORE_AKID          0x004 /* CRL issuer matches CRL AKID */
 #define CRL_SCORE_TIME_DELTA    0x002 /* Have a delta CRL with valid times */
 
+static int x509_verify_x509(X509_STORE_CTX *ctx);
+static int x509_verify_rpk(X509_STORE_CTX *ctx);
 static int build_chain(X509_STORE_CTX *ctx);
 static int verify_chain(X509_STORE_CTX *ctx);
+static int verify_rpk(X509_STORE_CTX *ctx);
 static int dane_verify(X509_STORE_CTX *ctx);
+static int dane_verify_rpk(X509_STORE_CTX *ctx);
 static int null_callback(int ok, X509_STORE_CTX *e);
 static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
 static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
@@ -56,7 +60,8 @@ static int check_cert(X509_STORE_CTX *ctx);
 static int check_policy(X509_STORE_CTX *ctx);
 static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
 static int check_dane_issuer(X509_STORE_CTX *ctx, int depth);
-static int check_key_level(X509_STORE_CTX *ctx, X509 *cert);
+static int check_cert_key_level(X509_STORE_CTX *ctx, X509 *cert);
+static int check_key_level(X509_STORE_CTX *ctx, EVP_PKEY *pkey);
 static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert);
 static int check_curve(X509 *cert);
 
@@ -197,7 +202,7 @@ static int check_auth_level(X509_STORE_CTX *ctx)
          * We've already checked the security of the leaf key, so here we only
          * check the security of issuer keys.
          */
-        CB_FAIL_IF(i > 0 && !check_key_level(ctx, cert),
+        CB_FAIL_IF(i > 0 && !check_cert_key_level(ctx, cert),
                    ctx, cert, i, X509_V_ERR_CA_KEY_TOO_SMALL);
         /*
          * We also check the signature algorithm security of all certificates
@@ -209,6 +214,20 @@ static int check_auth_level(X509_STORE_CTX *ctx)
     return 1;
 }
 
+/*-
+ * Returns -1 on internal error.
+ * Sadly, returns 0 also on internal error in ctx->verify_cb().
+ */
+static int verify_rpk(X509_STORE_CTX *ctx)
+{
+    /* Not much to verify on a RPK */
+    if (ctx->verify != NULL)
+        return ctx->verify(ctx);
+
+    return !!ctx->verify_cb(ctx->error == X509_V_OK, ctx);
+}
+
+
 /*-
  * Returns -1 on internal error.
  * Sadly, returns 0 also on internal error in ctx->verify_cb().
@@ -258,23 +277,58 @@ int X509_STORE_CTX_verify(X509_STORE_CTX *ctx)
         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
         return -1;
     }
+    if (ctx->rpk != NULL)
+        return x509_verify_rpk(ctx);
     if (ctx->cert == NULL && sk_X509_num(ctx->untrusted) >= 1)
         ctx->cert = sk_X509_value(ctx->untrusted, 0);
-    return X509_verify_cert(ctx);
+    return x509_verify_x509(ctx);
+}
+
+int X509_verify_cert(X509_STORE_CTX *ctx)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
+        return -1;
+    }
+    return (ctx->rpk != NULL) ? x509_verify_rpk(ctx) : x509_verify_x509(ctx);
 }
 
 /*-
  * Returns -1 on internal error.
  * Sadly, returns 0 also on internal error in ctx->verify_cb().
  */
-int X509_verify_cert(X509_STORE_CTX *ctx)
+static int x509_verify_rpk(X509_STORE_CTX *ctx)
+{
+    int ret;
+
+    /* If the peer's public key is too weak, we can stop early. */
+    if (!check_key_level(ctx, ctx->rpk)
+        && verify_cb_cert(ctx, NULL, 0, X509_V_ERR_EE_KEY_TOO_SMALL) == 0)
+        return 0;
+
+    /* Barring any data to verify the RPK, simply report it as untrusted */
+    ctx->error = X509_V_ERR_RPK_UNTRUSTED;
+
+    ret = DANETLS_ENABLED(ctx->dane) ? dane_verify_rpk(ctx) : verify_rpk(ctx);
+
+    /*
+     * Safety-net.  If we are returning an error, we must also set ctx->error,
+     * so that the chain is not considered verified should the error be ignored
+     * (e.g. TLS with SSL_VERIFY_NONE).
+     */
+    if (ret <= 0 && ctx->error == X509_V_OK)
+        ctx->error = X509_V_ERR_UNSPECIFIED;
+    return ret;
+}
+
+/*-
+ * Returns -1 on internal error.
+ * Sadly, returns 0 also on internal error in ctx->verify_cb().
+ */
+static int x509_verify_x509(X509_STORE_CTX *ctx)
 {
     int ret;
 
-    if (ctx == NULL) {
-        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
-        return -1;
-    }
     if (ctx->cert == NULL) {
         ERR_raise(ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
         ctx->error = X509_V_ERR_INVALID_CALL;
@@ -298,7 +352,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
     ctx->num_untrusted = 1;
 
     /* If the peer's public key is too weak, we can stop early. */
-    CB_FAIL_IF(!check_key_level(ctx, ctx->cert),
+    CB_FAIL_IF(!check_cert_key_level(ctx, ctx->cert),
                ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL);
 
     ret = DANETLS_ENABLED(ctx->dane) ? dane_verify(ctx) : verify_chain(ctx);
@@ -1758,9 +1812,19 @@ int ossl_x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
  */
 static int internal_verify(X509_STORE_CTX *ctx)
 {
-    int n = sk_X509_num(ctx->chain) - 1;
-    X509 *xi = sk_X509_value(ctx->chain, n);
-    X509 *xs = xi;
+    int n;
+    X509 *xi;
+    X509 *xs;
+
+    /* For RPK: just do the verify callback */
+    if (ctx->rpk != NULL) {
+        if (!ctx->verify_cb(ctx->error == X509_V_OK, ctx))
+            return 0;
+        return 1;
+    }
+    n = sk_X509_num(ctx->chain) - 1;
+    xi = sk_X509_value(ctx->chain, n);
+    xs = xi;
 
     ctx->error_depth = n;
     if (ctx->bare_ta_signed) {
@@ -2227,6 +2291,11 @@ void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x)
     ctx->cert = x;
 }
 
+void X509_STORE_CTX_set0_rpk(X509_STORE_CTX *ctx, EVP_PKEY *rpk)
+{
+    ctx->rpk = rpk;
+}
+
 void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk)
 {
     ctx->crls = sk;
@@ -2348,6 +2417,15 @@ void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
     OPENSSL_free(ctx);
 }
 
+
+int X509_STORE_CTX_init_rpk(X509_STORE_CTX *ctx, X509_STORE *store, EVP_PKEY *rpk)
+{
+    if (!X509_STORE_CTX_init(ctx, store, NULL, NULL))
+        return 0;
+    ctx->rpk = rpk;
+    return 1;
+}
+
 int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
                         STACK_OF(X509) *chain)
 {
@@ -2377,6 +2455,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
     ctx->parent = NULL;
     ctx->dane = NULL;
     ctx->bare_ta_signed = 0;
+    ctx->rpk = NULL;
     /* Zero ex_data to make sure we're cleanup-safe */
     memset(&ctx->ex_data, 0, sizeof(ctx->ex_data));
 
@@ -2540,6 +2619,11 @@ X509 *X509_STORE_CTX_get0_cert(const X509_STORE_CTX *ctx)
     return ctx->cert;
 }
 
+EVP_PKEY *X509_STORE_CTX_get0_rpk(const X509_STORE_CTX *ctx)
+{
+    return ctx->rpk;
+}
+
 STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(const X509_STORE_CTX *ctx)
 {
     return ctx->untrusted;
@@ -2712,7 +2796,7 @@ static unsigned char *dane_i2d(X509 *cert, uint8_t selector,
 #define DANETLS_NONE 256 /* impossible uint8_t */
 
 /* Returns -1 on internal error */
-static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth)
+static int dane_match_cert(X509_STORE_CTX *ctx, X509 *cert, int depth)
 {
     SSL_DANE *dane = ctx->dane;
     unsigned usage = DANETLS_NONE;
@@ -2870,7 +2954,7 @@ static int check_dane_issuer(X509_STORE_CTX *ctx, int depth)
      * for an exact match for the leaf certificate).
      */
     cert = sk_X509_value(ctx->chain, depth);
-    if (cert != NULL && (matched = dane_match(ctx, cert, depth)) < 0)
+    if (cert != NULL && (matched = dane_match_cert(ctx, cert, depth)) < 0)
         return matched;
     if (matched > 0) {
         ctx->num_untrusted = depth - 1;
@@ -2917,6 +3001,62 @@ static int check_dane_pkeys(X509_STORE_CTX *ctx)
     return X509_TRUST_UNTRUSTED;
 }
 
+/*
+ * Only DANE-EE and SPKI are supported
+ * Returns -1 on internal error
+ */
+static int dane_match_rpk(X509_STORE_CTX *ctx, EVP_PKEY *rpk)
+{
+    SSL_DANE *dane = ctx->dane;
+    danetls_record *t = NULL;
+    int mtype = DANETLS_MATCHING_FULL;
+    unsigned char *i2dbuf = NULL;
+    unsigned int i2dlen = 0;
+    unsigned char mdbuf[EVP_MAX_MD_SIZE];
+    unsigned char *cmpbuf;
+    unsigned int cmplen = 0;
+    int len;
+    int recnum = sk_danetls_record_num(dane->trecs);
+    int i;
+    int matched = 0;
+
+    /* Calculate ASN.1 DER of RPK */
+    if ((len = i2d_PUBKEY(rpk, &i2dbuf)) <= 0)
+        return -1;
+    cmplen = i2dlen = (unsigned int)len;
+    cmpbuf = i2dbuf;
+
+    for (i = 0; i < recnum; i++) {
+        t = sk_danetls_record_value(dane->trecs, i);
+        if (t->usage != DANETLS_USAGE_DANE_EE || t->selector != DANETLS_SELECTOR_SPKI)
+            continue;
+
+        /* Calculate hash - keep only one around */
+        if (t->mtype != mtype) {
+            const EVP_MD *md = dane->dctx->mdevp[mtype = t->mtype];
+
+            cmpbuf = i2dbuf;
+            cmplen = i2dlen;
+
+            if (md != NULL) {
+                cmpbuf = mdbuf;
+                if (!EVP_Digest(i2dbuf, i2dlen, cmpbuf, &cmplen, md, 0)) {
+                    matched = -1;
+                    break;
+                }
+            }
+        }
+        if (cmplen == t->dlen && memcmp(cmpbuf, t->data, cmplen) == 0) {
+            matched = 1;
+            dane->mdpth = 0;
+            dane->mtlsa = t;
+            break;
+        }
+    }
+    OPENSSL_free(i2dbuf);
+    return matched;
+}
+
 static void dane_reset(SSL_DANE *dane)
 {
     /* Reset state to verify another chain, or clear after failure. */
@@ -2936,6 +3076,36 @@ static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert)
     return 1;
 }
 
+/* Returns -1 on internal error */
+static int dane_verify_rpk(X509_STORE_CTX *ctx)
+{
+    SSL_DANE *dane = ctx->dane;
+    int matched;
+
+    dane_reset(dane);
+
+    /*
+     * Look for a DANE record for RPK
+     * If error, return -1
+     * If found, call ctx->verify_cb(1, ctx)
+     * If not found call ctx->verify_cb(0, ctx)
+     */
+    matched = dane_match_rpk(ctx, ctx->rpk);
+    ctx->error_depth = 0;
+
+    if (matched < 0) {
+        ctx->error = X509_V_ERR_UNSPECIFIED;
+        return -1;
+    }
+
+    if (matched > 0)
+        ctx->error = X509_V_OK;
+    else
+        ctx->error = X509_V_ERR_DANE_NO_MATCH;
+
+    return verify_rpk(ctx);
+}
+
 /* Returns -1 on internal error */
 static int dane_verify(X509_STORE_CTX *ctx)
 {
@@ -2958,7 +3128,7 @@ static int dane_verify(X509_STORE_CTX *ctx)
      *   + matched == 0, mdepth < 0 (no PKIX-EE match) and there are no
      *     DANE-TA(2) or PKIX-TA(0) to test.
      */
-    matched = dane_match(ctx, ctx->cert, 0);
+    matched = dane_match_cert(ctx, ctx->cert, 0);
     done = matched != 0 || (!DANETLS_HAS_TA(dane) && dane->mdpth < 0);
 
     if (done && !X509_get_pubkey_parameters(NULL, ctx->chain))
@@ -3416,12 +3586,11 @@ static const int minbits_table[] = { 80, 112, 128, 192, 256 };
 static const int NUM_AUTH_LEVELS = OSSL_NELEM(minbits_table);
 
 /*-
- * Check whether the public key of `cert` meets the security level of `ctx`.
+ * Check whether the given public key meets the security level of `ctx`.
  * Returns 1 on success, 0 otherwise.
  */
-static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
+static int check_key_level(X509_STORE_CTX *ctx, EVP_PKEY *pkey)
 {
-    EVP_PKEY *pkey = X509_get0_pubkey(cert);
     int level = ctx->param->auth_level;
 
     /*
@@ -3443,6 +3612,15 @@ static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
     return EVP_PKEY_get_security_bits(pkey) >= minbits_table[level - 1];
 }
 
+/*-
+ * Check whether the public key of `cert` meets the security level of `ctx`.
+ * Returns 1 on success, 0 otherwise.
+ */
+static int check_cert_key_level(X509_STORE_CTX *ctx, X509 *cert)
+{
+    return check_key_level(ctx, X509_get0_pubkey(cert));
+}
+
 /*-
  * Check whether the public key of ``cert`` does not use explicit params
  * for an elliptic curve.
index a7897abdb3b8932f4273b7bc2792c0506b554095..f857adb5e13f55c9d70cd3f97c30ff297c34d64a 100644 (file)
@@ -2483,6 +2483,10 @@ DEPEND[html/man3/SSL_free.html]=man3/SSL_free.pod
 GENERATE[html/man3/SSL_free.html]=man3/SSL_free.pod
 DEPEND[man/man3/SSL_free.3]=man3/SSL_free.pod
 GENERATE[man/man3/SSL_free.3]=man3/SSL_free.pod
+DEPEND[html/man3/SSL_get0_peer_rpk.html]=man3/SSL_get0_peer_rpk.pod
+GENERATE[html/man3/SSL_get0_peer_rpk.html]=man3/SSL_get0_peer_rpk.pod
+DEPEND[man/man3/SSL_get0_peer_rpk.3]=man3/SSL_get0_peer_rpk.pod
+GENERATE[man/man3/SSL_get0_peer_rpk.3]=man3/SSL_get0_peer_rpk.pod
 DEPEND[html/man3/SSL_get0_peer_scts.html]=man3/SSL_get0_peer_scts.pod
 GENERATE[html/man3/SSL_get0_peer_scts.html]=man3/SSL_get0_peer_scts.pod
 DEPEND[man/man3/SSL_get0_peer_scts.3]=man3/SSL_get0_peer_scts.pod
@@ -2627,6 +2631,10 @@ DEPEND[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod
 GENERATE[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod
 DEPEND[man/man3/SSL_set1_host.3]=man3/SSL_set1_host.pod
 GENERATE[man/man3/SSL_set1_host.3]=man3/SSL_set1_host.pod
+DEPEND[html/man3/SSL_set1_server_cert_type.html]=man3/SSL_set1_server_cert_type.pod
+GENERATE[html/man3/SSL_set1_server_cert_type.html]=man3/SSL_set1_server_cert_type.pod
+DEPEND[man/man3/SSL_set1_server_cert_type.3]=man3/SSL_set1_server_cert_type.pod
+GENERATE[man/man3/SSL_set1_server_cert_type.3]=man3/SSL_set1_server_cert_type.pod
 DEPEND[html/man3/SSL_set_async_callback.html]=man3/SSL_set_async_callback.pod
 GENERATE[html/man3/SSL_set_async_callback.html]=man3/SSL_set_async_callback.pod
 DEPEND[man/man3/SSL_set_async_callback.3]=man3/SSL_set_async_callback.pod
@@ -3468,6 +3476,7 @@ html/man3/SSL_do_handshake.html \
 html/man3/SSL_export_keying_material.html \
 html/man3/SSL_extension_supported.html \
 html/man3/SSL_free.html \
+html/man3/SSL_get0_peer_rpk.html \
 html/man3/SSL_get0_peer_scts.html \
 html/man3/SSL_get_SSL_CTX.html \
 html/man3/SSL_get_all_async_fds.html \
@@ -3504,6 +3513,7 @@ html/man3/SSL_read_early_data.html \
 html/man3/SSL_rstate_string.html \
 html/man3/SSL_session_reused.html \
 html/man3/SSL_set1_host.html \
+html/man3/SSL_set1_server_cert_type.html \
 html/man3/SSL_set_async_callback.html \
 html/man3/SSL_set_bio.html \
 html/man3/SSL_set_blocking_mode.html \
@@ -4092,6 +4102,7 @@ man/man3/SSL_do_handshake.3 \
 man/man3/SSL_export_keying_material.3 \
 man/man3/SSL_extension_supported.3 \
 man/man3/SSL_free.3 \
+man/man3/SSL_get0_peer_rpk.3 \
 man/man3/SSL_get0_peer_scts.3 \
 man/man3/SSL_get_SSL_CTX.3 \
 man/man3/SSL_get_all_async_fds.3 \
@@ -4128,6 +4139,7 @@ man/man3/SSL_read_early_data.3 \
 man/man3/SSL_rstate_string.3 \
 man/man3/SSL_session_reused.3 \
 man/man3/SSL_set1_host.3 \
+man/man3/SSL_set1_server_cert_type.3 \
 man/man3/SSL_set_async_callback.3 \
 man/man3/SSL_set_bio.3 \
 man/man3/SSL_set_blocking_mode.3 \
index 86b9aff91e724c9140e89c29797d2413a938b763..aa785d8b2fe13e8090e542bf0470f6d02e5403a4 100644 (file)
@@ -132,6 +132,8 @@ B<openssl> B<s_client>
 {- $OpenSSL::safe::opt_provider_synopsis -}
 {- $OpenSSL::safe::opt_engine_synopsis -}[B<-ssl_client_engine> I<id>]
 {- $OpenSSL::safe::opt_v_synopsis -}
+[B<-enable_server_rpk>]
+[B<-enable_client_rpk>]
 [I<host>:I<port>]
 
 =head1 DESCRIPTION
@@ -825,6 +827,22 @@ Specify engine to be used for client certificate operations.
 Verification errors are displayed, for debugging, but the command will
 proceed unless the B<-verify_return_error> option is used.
 
+=item B<-enable_server_rpk>
+
+Enable support for receiving raw public keys (RFC7250) from the server.
+Use of X.509 certificates by the server becomes optional, and servers that
+support raw public keys may elect to use them.
+Servers that don't support raw public keys or prefer to use X.509
+certificates can still elect to send X.509 certificates as usual.
+
+=item B<-enable_client_rpk>
+
+Enable support for sending raw public keys (RFC7250) to the server.
+A raw public key will be sent by the client, if solicited by the server,
+provided a suitable key and public certificate pair is configured.
+Some servers may nevertheless not request any client credentials,
+or may request a certificate.
+
 =item I<host>:I<port>
 
 Rather than providing B<-connect>, the target hostname and optional port may
@@ -940,13 +958,17 @@ The B<-certform> option has become obsolete in OpenSSL 3.0.0 and has no effect.
 
 The B<-engine> option was deprecated in OpenSSL 3.0.
 
-
-The B<-tfo>, B<-no_tx_cert_comp>, and B<-no_rx_cert_comp> options were added
-in OpenSSL 3.2.
+The
+B<-enable_client_rpk>,
+B<-enable_server_rpk>,
+B<-no_rx_cert_comp>,
+B<-no_tx_cert_comp>,
+and B<-tfo>
+options were added in OpenSSL 3.2.
 
 =head1 COPYRIGHT
 
-Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index a1e354908c912951d0474f6ab8d2fc8c715910bc..611b410cfd63c83bd74c5da7530e5395c4d8b8fe 100644 (file)
@@ -151,6 +151,8 @@ B<openssl> B<s_server>
 {- $OpenSSL::safe::opt_trust_synopsis -}
 {- $OpenSSL::safe::opt_r_synopsis -}
 {- $OpenSSL::safe::opt_engine_synopsis -}{- $OpenSSL::safe::opt_provider_synopsis -}
+[B<-enable_server_rpk>]
+[B<-enable_client_rpk>]
 
 =head1 DESCRIPTION
 
@@ -867,6 +869,26 @@ If the server requests a client certificate, then
 verification errors are displayed, for debugging, but the command will
 proceed unless the B<-verify_return_error> option is used.
 
+=item B<-enable_server_rpk>
+
+Enable support for sending raw public keys (RFC7250) to the client.
+A raw public key will be sent by the server, if solicited by the client,
+provided a suitable key and public certificate pair is configured.
+Clients that don't support raw public keys or prefer to use X.509
+certificates can still elect to receive X.509 certificates as usual.
+
+Raw public keys are extracted from the configured certificate/private key.
+
+=item B<-enable_client_rpk>
+
+Enable support for receiving raw public keys (RFC7250) from the client.
+Use of X.509 certificates by the client becomes optional, and clients that
+support raw public keys may elect to use them.
+Clients that don't support raw public keys or prefer to use X.509
+certificates can still elect to send X.509 certificates as usual.
+
+Raw public keys are extracted from the configured certificate/private key.
+
 =back
 
 =head1 CONNECTED COMMANDS
@@ -971,12 +993,17 @@ The
 The B<-srpvfile>, B<-srpuserseed>, and B<-engine>
 option were deprecated in OpenSSL 3.0.
 
-The B<-tfo>, B<-no_tx_cert_comp>, and B<-no_rx_cert_comp> options were added
-in OpenSSL 3.2.
+The
+B<-enable_client_rpk>,
+B<-enable_server_rpk>,
+B<-no_rx_cert_comp>,
+B<-no_tx_cert_comp>,
+and B<-tfo>
+options were added in OpenSSL 3.2.
 
 =head1 COPYRIGHT
 
-Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index 5a3977b70a4fb73582f491c7c9e20f59c8af2672..1a466020a71131684005c59ecb1ba28de1824705 100644 (file)
@@ -306,10 +306,13 @@ the lifetime of the SSL connection.
      int depth = SSL_get0_dane_authority(ssl, NULL, &mspki);
      if (depth >= 0) {
          (void) SSL_get0_dane_tlsa(ssl, &usage, &selector, &mtype, NULL, NULL);
-         printf("DANE TLSA %d %d %d %s at depth %d\n", usage, selector, mtype,
-                (mspki != NULL) ? "TA public key verified certificate" :
-                depth ? "matched TA certificate" : "matched EE certificate",
-                depth);
+         printf("DANE TLSA %d %d %d ", usage, selector, mtype);
+         if (SSL_get0_peer_rpk(ssl) == NULL)
+             printf("%s certificate at depth %d\n",
+                    (mspki != NULL) ? "signed the peer" :
+                    mdpth ? "matched the TA" : "matched the EE", mdpth);
+         else
+             printf(bio, "matched the peer raw public key\n");
      }
      if (peername != NULL) {
          /* Name checks were in scope and matched the peername */
diff --git a/doc/man3/SSL_get0_peer_rpk.pod b/doc/man3/SSL_get0_peer_rpk.pod
new file mode 100644 (file)
index 0000000..5baa257
--- /dev/null
@@ -0,0 +1,99 @@
+=pod
+
+=head1 NAME
+
+SSL_add_expected_rpk,
+SSL_get_negotiated_client_cert_type,
+SSL_get_negotiated_server_cert_type,
+SSL_get0_peer_rpk,
+SSL_SESSION_get0_peer_rpk - raw public key (RFC7250) support
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk);
+ int SSL_get_negotiated_client_cert_type(const SSL *s);
+ int SSL_get_negotiated_server_cert_type(const SSL *s);
+ EVP_PKEY *SSL_get0_peer_rpk(const SSL *s);
+ EVP_PKEY *SSL_SESSION_get0_peer_rpk(const SSL_SESSION *ss);
+
+=head1 DESCRIPTION
+
+SSL_add_expected_rpk() adds a DANE TLSA record matching public key B<rpk>
+to SSL B<s>'s DANE validation policy.
+
+SSL_get_negotiated_client_cert_type() returns the connection's negotiated
+client certificate type.
+
+SSL_get_negotiated_server_cert_type() returns the connection's negotiated
+server certificate type.
+
+SSL_get0_peer_rpk() returns the peer's raw public key from SSL B<s>.
+
+SSL_SESSION_get0_peer_rpk() returns the peer's raw public key from
+SSL_SESSION B<ss>.
+
+=head1 NOTES
+
+Raw public keys are used in place of certificates when the option is
+negotiated.
+B<SSL_add_expected_rpk()> may be called multiple times to configure
+multiple trusted keys, this makes it possible to allow for key rotation,
+where a peer might be expected to offer an "old" or "new" key and the
+endpoint must be able to accept either one.
+
+When raw public keys are used, the certificate verify callback is called, and
+may be used to inspect the public key via X509_STORE_CTX_get0_rpk(3).
+Raw public keys have no subject, issuer, validity dates nor digital signature
+to verify. They can, however, be matched verbatim or by their digest value, this
+is done by specifying one or more TLSA records, see L<SSL_CTX_dane_enable(3)>.
+
+The raw public key is typically taken from the certificate assigned to the
+connection (e.g. via L<SSL_use_certificate(3)>), but if a certificate is not
+configured, then the public key will be extracted from the assigned
+private key.
+
+The SSL_add_expected_rpk() function is a wrapper around
+L<SSL_dane_tlsa_add(3)>.
+When DANE is enabled via L<SSL_dane_enable(3)>, the configured TLSA records
+will be used to validate the peer's public key or certificate.
+If DANE is not enabled, then no validation will occur.
+
+=head1 RETURN VALUES
+
+SSL_add_expected_rpk() returns 1 on success and 0 on failure.
+
+SSL_get0_peer_rpk() and SSL_SESSION_get0_peer_rpk() return the peer's raw
+public key as an EVP_PKEY or NULL when the raw public key is not available.
+
+SSL_get_negotiated_client_cert_type() and SSL_get_negotiated_server_cert_type()
+return one of the following values:
+
+=over 4
+
+=item TLSEXT_cert_type_x509
+
+=item TLSEXT_cert_type_rpk
+
+=back
+
+=head1 SEE ALSO
+
+L<SSL_CTX_dane_enable(3)>,
+L<SSL_CTX_set_options(3)>,
+L<SSL_dane_enable(3)>,
+L<SSL_get_verify_result(3)>,
+L<SSL_set_verify(3)>,
+L<SSL_use_certificate(3)>,
+L<X509_STORE_CTX_get0_rpk(3)>
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.2.
+
+=head1 COPYRIGHT
+
+Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+
+=cut
diff --git a/doc/man3/SSL_set1_server_cert_type.pod b/doc/man3/SSL_set1_server_cert_type.pod
new file mode 100644 (file)
index 0000000..aaa7fe0
--- /dev/null
@@ -0,0 +1,196 @@
+=pod
+
+=head1 NAME
+
+SSL_set1_client_cert_type,
+SSL_set1_server_cert_type,
+SSL_CTX_set1_client_cert_type,
+SSL_CTX_set1_server_cert_type,
+SSL_get0_client_cert_type,
+SSL_get0_server_cert_type,
+SSL_CTX_get0_client_cert_type,
+SSL_CTX_get0_server_cert_type - certificate type (RFC7250) support
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int SSL_set1_client_cert_type(SSL *s, const unsigned char *val, size_t len);
+ int SSL_set1_server_cert_type(SSL *s, const unsigned char *val, size_t len);
+ int SSL_CTX_set1_client_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len);
+ int SSL_CTX_set1_server_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len);
+ int SSL_get0_client_cert_type(const SSL *s, unsigned char **val, size_t *len);
+ int SSL_get0_server_cert_type(const SSL *s, unsigned char **val, size_t *len);
+ int SSL_CTX_get0_client_cert_type(const SSL_CTX *ctx, unsigned char **val, size_t *len);
+ int SSL_CTX_get0_server_cert_type(const SSL_CTX *s, unsigned char **val, size_t *len);
+
+=head1 DESCRIPTION
+
+The SSL_set1_client_cert_type() and SSL_CTX_set1_client_cert_type() functions
+set the values for the client certificate type extension.
+The SSL_get0_client_cert_type() and SSL_CTX_get0_client_cert_type() functions
+retrieve the local values to be used in the client certificate type extension.
+
+The SSL_set1_server_cert_type() and SSL_CTX_set1_server_cert_type() functions
+set the values for the server certificate type extension.
+The SSL_get0_server_cert_type() and SSL_CTX_get0_server_cert_type() functions
+retrieve the local values to be used in the server certificate type extension.
+
+=head1 NOTES
+
+The certificate type extensions are used to negotiate the certificate type to
+be used in the handshake.
+These extensions let each side know what its peer is able to accept.
+
+The client certificate type is sent from the client to the server to indicate
+what certificate types the client is able to present.
+Values are configured in preference order.
+On the server, this setting determines which certificate types the server is
+willing to accept.
+The server ultimately chooses what type to request (if any) from the values
+that are mutually supported.
+By default (if no explicit settings are specified), only X.509 certificates
+are supported.
+
+The server certificate type is sent from the client to the server to indicate
+what certificate types the client accepts.
+Values are configured in preference order.
+On the server, this setting determines which certificate types the server is
+willing to present.
+The server ultimately chooses what type to use from the values that are
+mutually supported.
+By default (if no explicit settings are specified), only X.509 certificates
+are supported.
+
+Having RPK specified first means that side will attempt to send (or request)
+RPKs if its peer also supports RPKs, otherwise X.509 certificate will be used
+if both have specified that (or have not configured these options).
+
+The two supported values in the B<val> array are:
+
+=over 4
+
+=item TLSEXT_cert_type_x509
+
+Which corresponds to an X.509 certificate normally used in TLS.
+
+=item TLSEXT_cert_type_rpk
+
+Which corresponds to a raw public key.
+
+=back
+
+If B<val> is set to a non-NULL value, then the extension is sent in the handshake.
+If b<val> is set to a NULL value (and B<len> is 0), then the extension is
+disabled. The default value is NULL, meaning the extension is not sent, and
+X.509 certificates are used in the handshake.
+
+Raw public keys may be used in place of certificates when specified in the
+certificate type and negotiated.
+Raw public keys have no subject, issuer, validity dates or digital signature.
+
+Use the L<SSL_get_negotiated_client_cert_type(3)> and
+L<SSL_get_negotiated_server_cert_type(3)> functions to get the negotiated cert
+type values (at the conclusion of the handshake, or in callbacks that happen
+after the TLS ServerHello has been processed).
+
+=head1 RETURN VALUES
+
+All functions return 1 on success and 0 on failure.
+
+The memory returned from the get0 functions must not be freed.
+
+=head1 EXAMPLES
+
+To use raw public keys on the server, set up the SSL_CTX and SSL as follows:
+
+ SSL_CTX *ctx;
+ SSL *ssl;
+ unsigned char cert_type[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
+ EVP_PKEY *rpk;
+
+ /* Assign rpk to an EVP_PKEY from a file or other means */
+
+ if ((ctx = SSL_CTX_new(TLS_server_method())) == NULL)
+     /* error */
+ if ((ssl = SSL_new(ctx)) == NULL)
+     /* error */
+ if (!SSL_set1_server_cert_type(ssl, cert_type, sizeof(cert_type)))
+     /* error */
+
+ /* A certificate does not need to be specified when using raw public keys */
+ if (!SSL_use_PrivateKey(ssl, rpk))
+     /* error */
+
+ /* Perform SSL_accept() operations */
+
+To connect to this server, set the client SSL_CTX and SSL as follows:
+
+ /* Connect function */
+
+ SSL_CTX *ctx;
+ SSL *ssl;
+ const char *dane_tlsa_domain = "smtp.example.com";
+ unsigned char cert_type[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
+ EVP_PKEY *rpk;
+ int verify_result;
+
+ /* Assign rpk to an EVP_PKEY from a file or other means */
+
+ if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL)
+     /* error */
+ if (SSL_CTX_dane_enable(ctx) <= 0)
+     /* error */
+ if ((ssl = SSL_new(ctx)) == NULL)
+     /* error */
+ /*
+  * The `dane_tlsa_domain` arguments sets the default SNI hostname.
+  * It may be set to NULL when enabling DANE on the server side.
+  */
+ if (SSL_dane_enable(ssl, dane_tlsa_domain) <= 0)
+     /* error */
+ if (!SSL_set1_server_cert_type(ssl, cert_type, sizeof(cert_type)))
+     /* error */
+ if (!SSL_add_expected_rpk(ssl, rpk))
+     /* error */
+
+ /* Do SSL_connect() handshake and handle errors here */
+
+ /* Optional: verify the peer RPK */ 
+ verify_result = SSL_get_verify_result(ssl);
+ if (verify_result == X509_V_OK) {
+     /* The server's raw public key matched the TLSA record */
+ } else if (verify_result == X509_V_ERR_DANE_NO_MATCH) {
+     /*
+      * The server's raw public key, or public key in certificate, did not
+      * match the TLSA record
+      */
+ } else if (verify_result == X509_V_ERR_RPK_UNTRUSTED) {
+     /*
+      * No TLSA records of the correct type are available to verify the
+      * server's raw public key. This would not happen in this example,
+      * as a TLSA record is configured.
+      */
+ } else {
+     /* Some other verify error */
+ }
+
+To validate client raw public keys, code from the client example may need to be
+incorporated into the server side.
+
+=head1 SEE ALSO
+
+L<SSL_get0_peer_rpk(3)>,
+L<SSL_get_negotiated_client_cert_type(3)>,
+L<SSL_get_negotiated_server_cert_type(3)>,
+L<SSL_use_certificate(3)>
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.2.
+
+=head1 COPYRIGHT
+
+Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+
+=cut
index 123ecdc9b4c3b1b49acd608bf212e855388c4047..1ecea800046c4eb38f753c2ac7bda8e997e4c3f8 100644 (file)
@@ -67,7 +67,8 @@ Once such a I<saved> certificate is no longer needed it can be freed with
 L<X509_free(3)>.
 
 X509_STORE_CTX_get0_cert() retrieves an internal pointer to the
-certificate being verified by the I<ctx>.
+certificate being verified by the I<ctx>. It may be NULL if a raw public
+key is being verified.
 
 X509_STORE_CTX_get1_chain() returns a complete validate chain if a previous
 verification is successful. Otherwise the returned chain may be incomplete or
@@ -460,6 +461,11 @@ The algorithm given in the certificate info is inconsistent
 A CA certificate is invalid. Either it is not a CA or its extensions are not
 consistent with the supplied purpose.
 
+=item B<X509_V_ERR_RPK_UNTRUSTED: raw public key untrusted, no trusted keys configured>
+
+No TLS records were configured to validate the raw public key, or DANE was not
+enabled on the connection.
+
 =back
 
 =head1 NOTES
@@ -490,7 +496,7 @@ L<X509_free(3)>.
 
 =head1 COPYRIGHT
 
-Copyright 2009-2021 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2009-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index d12dbfb8037c6af594e8d9e65403b8ad97e7a944..7a347197678443ca1244d2755d4b6c28a686d555 100644 (file)
@@ -3,12 +3,16 @@
 =head1 NAME
 
 X509_STORE_CTX_new_ex, X509_STORE_CTX_new, X509_STORE_CTX_cleanup,
-X509_STORE_CTX_free, X509_STORE_CTX_init, X509_STORE_CTX_set0_trusted_stack,
+X509_STORE_CTX_free, X509_STORE_CTX_init,
+X509_STORE_CTX_init_rpk,
+X509_STORE_CTX_set0_trusted_stack,
 X509_STORE_CTX_set_cert, X509_STORE_CTX_set0_crls,
+X509_STORE_CTX_set0_rpk,
 X509_STORE_CTX_get0_param, X509_STORE_CTX_set0_param,
 X509_STORE_CTX_get0_untrusted, X509_STORE_CTX_set0_untrusted,
 X509_STORE_CTX_get_num_untrusted,
 X509_STORE_CTX_get0_chain, X509_STORE_CTX_set0_verified_chain,
+X509_STORE_CTX_get0_rpk,
 X509_STORE_CTX_set_default,
 X509_STORE_CTX_set_verify,
 X509_STORE_CTX_verify_fn,
@@ -28,11 +32,14 @@ X509_STORE_CTX_purpose_inherit
 
  int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *trust_store,
                          X509 *target, STACK_OF(X509) *untrusted);
+ int X509_STORE_CTX_init_rpk(X509_STORE_CTX *ctx, X509_STORE *trust_store,
+                             EVP_PKEY *rpk);
 
  void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
 
  void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *target);
  void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk);
+ void X509_STORE_CTX_set0_rpk(X509_STORE_CTX *ctx, EVP_PKEY *target);
 
  X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(const X509_STORE_CTX *ctx);
  void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param);
@@ -43,6 +50,7 @@ X509_STORE_CTX_purpose_inherit
  int X509_STORE_CTX_get_num_untrusted(const X509_STORE_CTX *ctx);
  STACK_OF(X509) *X509_STORE_CTX_get0_chain(const X509_STORE_CTX *ctx);
  void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *chain);
+ EVP_PKEY *X509_STORE_CTX_get0_rpk(const X509_STORE_CTX *ctx);
 
  int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name);
  typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *);
@@ -85,6 +93,8 @@ they are provided simply as a list using X509_STORE_CTX_set0_trusted_stack().
 The certificate to be verified is set to I<target>,
 and a list of additional certificates may be provided in I<untrusted>,
 which will be untrusted but may be used to build the chain.
+The I<target> certificate is not copied (its reference count is not updated),
+and the caller must not free it before verification is complete.
 Each of the I<trust_store>, I<target> and I<untrusted> parameters can be NULL.
 Yet note that L<X509_verify_cert(3)> and L<X509_STORE_CTX_verify(3)>
 will need a verification target.
@@ -93,6 +103,14 @@ For L<X509_STORE_CTX_verify(3)>, which takes by default the first element of the
 list of untrusted certificates as its verification target,
 this can be also set indirectly using X509_STORE_CTX_set0_untrusted().
 
+X509_STORE_CTX_init_rpk() sets up I<ctx> for a subsequent verification
+operation for the I<target> raw public key.
+It behaves similarly to X509_STORE_CTX_init().
+The I<target> raw public key can aslo be supplied separately, via
+X509_STORE_CTX_set0_rpk().
+The I<target> public key is not copied (its reference count is not updated),
+and the caller must not free it before verification is complete.
+
 X509_STORE_CTX_set0_trusted_stack() sets the set of trusted certificates of
 I<ctx> to I<sk>. This is an alternative way of specifying trusted certificates
 instead of using an B<X509_STORE> where its complexity is not needed
@@ -100,6 +118,14 @@ or to make sure that only the given set I<sk> of certificates are trusted.
 
 X509_STORE_CTX_set_cert() sets the target certificate to be verified in I<ctx>
 to I<target>.
+The target certificate is not copied (its reference count is not updated),
+and the caller must not free it before verification is complete.
+
+X509_STORE_CTX_set0_rpk() sets the target raw public key to be verified in I<ctx>
+to I<target>, a non-NULL raw public key preempts any target certificate, which
+is then ignored.
+The I<target> public key is not copied (its reference count is not updated),
+and the caller must not free it before verification is complete.
 
 X509_STORE_CTX_set0_verified_chain() sets the validated chain to I<chain>.
 Ownership of the chain is transferred to I<ctx>,
@@ -108,6 +134,9 @@ and so it should not be free'd by the caller.
 X509_STORE_CTX_get0_chain() returns the internal pointer used by the
 I<ctx> that contains the constructed (output) chain.
 
+X509_STORE_CTX_get0_rpk() returns the internal pointer used by the
+I<ctx> that contains the raw public key.
+
 X509_STORE_CTX_set0_crls() sets a set of CRLs to use to aid certificate
 verification to I<sk>. These CRLs will only be used if CRL verification is
 enabled in the associated B<X509_VERIFY_PARAM> structure. This might be
@@ -247,11 +276,15 @@ should be made or reference counts increased instead.
 X509_STORE_CTX_new() returns a newly allocated context or NULL if an
 error occurred.
 
-X509_STORE_CTX_init() returns 1 for success or 0 if an error occurred.
+X509_STORE_CTX_init() and X509_STORE_CTX_init_rpk() return 1 for success
+or 0 if an error occurred.
 
 X509_STORE_CTX_get0_param() returns a pointer to an B<X509_VERIFY_PARAM>
 structure or NULL if an error occurred.
 
+X509_STORE_CTX_get0_rpk() returns a pointer to an B<EVP_PKEY> structure if
+present, or NULL if absent.
+
 X509_STORE_CTX_cleanup(), X509_STORE_CTX_free(),
 X509_STORE_CTX_set0_trusted_stack(),
 X509_STORE_CTX_set_cert(),
@@ -273,12 +306,14 @@ L<X509_VERIFY_PARAM_set_flags(3)>
 The X509_STORE_CTX_set0_crls() function was added in OpenSSL 1.0.0.
 The X509_STORE_CTX_get_num_untrusted() function was added in OpenSSL 1.1.0.
 The X509_STORE_CTX_new_ex() function was added in OpenSSL 3.0.
+The X509_STORE_CTX_init_rpk(), X509_STORE_CTX_get0_rpk(), and
+X509_STORE_CTX_set0_rpk() functions were added in OpenSSL 3.2.
 
 There is no need to call X509_STORE_CTX_cleanup() explicitly since OpenSSL 3.0.
 
 =head1 COPYRIGHT
 
-Copyright 2009-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2009-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index ad22721bd1ac80d06490ac231d6e8d7f70a4e173..8cdb2154ae511ff1b18b211f0ba7e22a9d8d998c 100644 (file)
@@ -73,7 +73,7 @@ X509_REQ_verify_ex(), and X509_self_signed() were added in OpenSSL 3.0.
 
 =head1 COPYRIGHT
 
-Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index d54acfdb0bd47ab7e91601c21502fa51be22c1b7..360e974812737b9e885563bc781c3121d89ea86e 100644 (file)
@@ -59,6 +59,14 @@ The X509_STORE_CTX_verify() behaves like X509_verify_cert() except that its
 target certificate is the first element of the list of untrusted certificates
 in I<ctx> unless a target certificate is set explicitly.
 
+When the verification target is a raw public key, rather than a certificate,
+both functions validate the target raw public key.
+In that case the number of possible checks is significantly reduced.
+The raw public key can be authenticated only via DANE TLSA records, either
+locally synthesised or obtained by the application from DNS.
+Raw public key DANE TLSA records may be added via L<SSL_add_expected_rpk(3)> or
+L<SSL_dane_tlsa_add(3)>.
+
 =head1 RETURN VALUES
 
 X509_build_chain() returns NULL on error, else a stack of certificates.
@@ -80,7 +88,12 @@ X509_V_OK, likely because a verification callback function has waived the error.
 
 =head1 SEE ALSO
 
-L<X509_STORE_CTX_new(3)>, L<X509_STORE_CTX_init(3)>,
+L<SSL_add_expected_rpk(3)>,
+L<SSL_CTX_dane_enable(3)>,
+L<SSL_dane_tlsa_add(3)>,
+L<X509_STORE_CTX_new(3)>,
+L<X509_STORE_CTX_init(3)>,
+L<X509_STORE_CTX_init_rpk(3)>,
 L<X509_STORE_CTX_get_error(3)>
 
 =head1 HISTORY
@@ -89,7 +102,7 @@ X509_build_chain() and X509_STORE_CTX_verify() were added in OpenSSL 3.0.
 
 =head1 COPYRIGHT
 
-Copyright 2009-2022 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2009-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index fe8308c2bf0bf00affb0c694d69dd8a4438c067e..2f3efff318553976cf21cf56037ac17989af2337 100644 (file)
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-d2i_SSL_SESSION, i2d_SSL_SESSION - convert SSL_SESSION object from/to ASN1 representation
+d2i_SSL_SESSION, d2i_SSL_SESSION_ex, i2d_SSL_SESSION - convert SSL_SESSION object from/to ASN1 representation
 
 =head1 SYNOPSIS
 
@@ -10,6 +10,9 @@ d2i_SSL_SESSION, i2d_SSL_SESSION - convert SSL_SESSION object from/to ASN1 repre
 
  SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
                               long length);
+ SSL_SESSION *d2i_SSL_SESSION_ex(SSL_SESSION **a, const unsigned char **pp,
+                                 long length, OSSL_LIB_CTX *libctx,
+                                 const char *propq);
  int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
 
 =head1 DESCRIPTION
@@ -25,8 +28,9 @@ from this SSL_CTX object).
 
 =head1 RETURN VALUES
 
-d2i_SSL_SESSION() returns a pointer to the newly allocated SSL_SESSION
-object. In case of failure the NULL-pointer is returned and the error message
+d2i_SSL_SESSION() and d2i_SSL_SESSION_ex() return a pointer to the newly
+allocated SSL_SESSION object.
+In case of failure the NULL-pointer is returned and the error message
 can be retrieved from the error stack.
 
 i2d_SSL_SESSION() returns the size of the ASN1 representation in bytes.
@@ -40,7 +44,7 @@ L<d2i_X509(3)>
 
 =head1 COPYRIGHT
 
-Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the Apache License 2.0 (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
index 596db8c163e05b170ef11cfeaecf488941c75c19..eaa43ba1585ebb99a42609dcec9580fcd326e9aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -278,6 +278,8 @@ struct x509_store_ctx_st {      /* X509_STORE_CTX */
     SSL_DANE *dane;
     /* signed via bare TA public key, rather than CA certificate */
     int bare_ta_signed;
+    /* Raw Public Key */
+    EVP_PKEY *rpk;
 
     OSSL_LIB_CTX *libctx;
     char *propq;
index a50378f27dda0d1e2772efac903801e7d12aee52..5cf6b319dc4de63d1351d14569b0ffc45a1d785e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * {- join("\n * ", @autowarntext) -}
  *
- * 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.
  *
@@ -258,29 +258,31 @@ typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
 
 /* Extension context codes */
 /* This extension is only allowed in TLS */
-#define SSL_EXT_TLS_ONLY                        0x0001
+#define SSL_EXT_TLS_ONLY                        0x00001
 /* This extension is only allowed in DTLS */
-#define SSL_EXT_DTLS_ONLY                       0x0002
+#define SSL_EXT_DTLS_ONLY                       0x00002
 /* Some extensions may be allowed in DTLS but we don't implement them for it */
-#define SSL_EXT_TLS_IMPLEMENTATION_ONLY         0x0004
+#define SSL_EXT_TLS_IMPLEMENTATION_ONLY         0x00004
 /* Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is */
-#define SSL_EXT_SSL3_ALLOWED                    0x0008
+#define SSL_EXT_SSL3_ALLOWED                    0x00008
 /* Extension is only defined for TLS1.2 and below */
-#define SSL_EXT_TLS1_2_AND_BELOW_ONLY           0x0010
+#define SSL_EXT_TLS1_2_AND_BELOW_ONLY           0x00010
 /* Extension is only defined for TLS1.3 and above */
-#define SSL_EXT_TLS1_3_ONLY                     0x0020
+#define SSL_EXT_TLS1_3_ONLY                     0x00020
 /* Ignore this extension during parsing if we are resuming */
-#define SSL_EXT_IGNORE_ON_RESUMPTION            0x0040
-#define SSL_EXT_CLIENT_HELLO                    0x0080
+#define SSL_EXT_IGNORE_ON_RESUMPTION            0x00040
+#define SSL_EXT_CLIENT_HELLO                    0x00080
 /* Really means TLS1.2 or below */
-#define SSL_EXT_TLS1_2_SERVER_HELLO             0x0100
-#define SSL_EXT_TLS1_3_SERVER_HELLO             0x0200
-#define SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS     0x0400
-#define SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST      0x0800
-#define SSL_EXT_TLS1_3_CERTIFICATE              0x1000
-#define SSL_EXT_TLS1_3_NEW_SESSION_TICKET       0x2000
-#define SSL_EXT_TLS1_3_CERTIFICATE_REQUEST      0x4000
-#define SSL_EXT_TLS1_3_CERTIFICATE_COMPRESSION  0x8000
+#define SSL_EXT_TLS1_2_SERVER_HELLO             0x00100
+#define SSL_EXT_TLS1_3_SERVER_HELLO             0x00200
+#define SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS     0x00400
+#define SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST      0x00800
+#define SSL_EXT_TLS1_3_CERTIFICATE              0x01000
+#define SSL_EXT_TLS1_3_NEW_SESSION_TICKET       0x02000
+#define SSL_EXT_TLS1_3_CERTIFICATE_REQUEST      0x04000
+#define SSL_EXT_TLS1_3_CERTIFICATE_COMPRESSION  0x08000
+/* When sending a raw public key in a certificate message */
+#define SSL_EXT_TLS1_3_RAW_PUBLIC_KEY           0x10000
 
 /* Typedefs for handling custom extensions */
 
@@ -566,6 +568,8 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
 # define CERT_PKEY_CERT_TYPE     0x400
 /* Cert chain suitable to Suite B */
 # define CERT_PKEY_SUITEB        0x800
+/* Cert pkey valid for raw public key use */
+# define CERT_PKEY_RPK           0x1000
 
 # define SSL_CONF_FLAG_CMDLINE           0x1
 # define SSL_CONF_FLAG_FILE              0x2
@@ -1734,6 +1738,9 @@ __owur int SSL_has_matching_session_id(const SSL *s,
                                        unsigned int id_len);
 SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
                              long length);
+SSL_SESSION *d2i_SSL_SESSION_ex(SSL_SESSION **a, const unsigned char **pp,
+                                long length, OSSL_LIB_CTX *libctx,
+                                const char *propq);
 
 # ifdef OPENSSL_X509_H
 __owur X509 *SSL_get0_peer_certificate(const SSL *s);
@@ -2592,6 +2599,20 @@ int SSL_set1_compressed_cert(SSL *ssl, int algorithm, unsigned char *comp_data,
 size_t SSL_CTX_get1_compressed_cert(SSL_CTX *ctx, int alg, unsigned char **data, size_t *orig_len);
 size_t SSL_get1_compressed_cert(SSL *ssl, int alg, unsigned char **data, size_t *orig_len);
 
+__owur int SSL_add_expected_rpk(SSL *s, EVP_PKEY *rpk);
+__owur EVP_PKEY *SSL_get0_peer_rpk(const SSL *s);
+__owur EVP_PKEY *SSL_SESSION_get0_peer_rpk(SSL_SESSION *s);
+__owur int SSL_get_negotiated_client_cert_type(const SSL *s);
+__owur int SSL_get_negotiated_server_cert_type(const SSL *s);
+
+__owur int SSL_set1_client_cert_type(SSL *s, const unsigned char *val, size_t len);
+__owur int SSL_set1_server_cert_type(SSL *s, const unsigned char *val, size_t len);
+__owur int SSL_CTX_set1_client_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len);
+__owur int SSL_CTX_set1_server_cert_type(SSL_CTX *ctx, const unsigned char *val, size_t len);
+__owur int SSL_get0_client_cert_type(const SSL *s, unsigned char **t, size_t *len);
+__owur int SSL_get0_server_cert_type(const SSL *s, unsigned char **t, size_t *len);
+__owur int SSL_CTX_get0_client_cert_type(const SSL_CTX *ctx, unsigned char **t, size_t *len);
+__owur int SSL_CTX_get0_server_cert_type(const SSL_CTX *s, unsigned char **t, size_t *len);
 
 # ifdef  __cplusplus
 }
index 43aa1c3742655f2691015a71a1dbe358467d8bfd..94cb60f8be62600cb41d68ffb64d033d229a9ea9 100644 (file)
@@ -25,6 +25,7 @@
 # define SSL_R_APP_DATA_IN_HANDSHAKE                      100
 # define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
 # define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE     158
+# define SSL_R_BAD_CERTIFICATE                            348
 # define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
 # define SSL_R_BAD_CIPHER                                 186
 # define SSL_R_BAD_COMPRESSION_ALGORITHM                  326
 # define SSL_R_ECC_CERT_NOT_FOR_SIGNING                   318
 # define SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE              374
 # define SSL_R_EE_KEY_TOO_SMALL                           399
+# define SSL_R_EMPTY_RAW_PUBLIC_KEY                       349
 # define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST         354
 # define SSL_R_ENCRYPTED_LENGTH_TOO_LONG                  150
 # define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST              151
 # define SSL_R_INVALID_KEY_UPDATE_TYPE                    120
 # define SSL_R_INVALID_MAX_EARLY_DATA                     174
 # define SSL_R_INVALID_NULL_CMD_NAME                      385
+# define SSL_R_INVALID_RAW_PUBLIC_KEY                     350
 # define SSL_R_INVALID_RECORD                             317
 # define SSL_R_INVALID_SEQUENCE_NUMBER                    402
 # define SSL_R_INVALID_SERVERINFO_DATA                    388
 # define SSL_R_WRONG_CERTIFICATE_TYPE                     383
 # define SSL_R_WRONG_CIPHER_RETURNED                      261
 # define SSL_R_WRONG_CURVE                                378
+# define SSL_R_WRONG_RPK_TYPE                             351
 # define SSL_R_WRONG_SIGNATURE_LENGTH                     264
 # define SSL_R_WRONG_SIGNATURE_SIZE                       265
 # define SSL_R_WRONG_SIGNATURE_TYPE                       370
index bb9314a9baa852261b7cf7d6c44122f9d54349d2..7e3d1a725b82e020dcd4dc20a3872fd203b600d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2021 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.
  *
@@ -122,6 +122,14 @@ extern "C" {
  */
 # define TLSEXT_TYPE_signed_certificate_timestamp    18
 
+/*
+ * Extension type for Raw Public Keys
+ * https://tools.ietf.org/html/rfc7250
+ * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+ */
+# define TLSEXT_TYPE_client_cert_type   19
+# define TLSEXT_TYPE_server_cert_type   20
+
 /*
  * ExtensionType value for TLS padding extension.
  * http://tools.ietf.org/html/draft-agl-tls-padding
@@ -224,6 +232,15 @@ extern "C" {
 # define TLSEXT_max_fragment_length_2048        3
 # define TLSEXT_max_fragment_length_4096        4
 
+/*
+ * TLS Certificate Type (for RFC7250)
+ * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-3
+ */
+# define TLSEXT_cert_type_x509         0
+# define TLSEXT_cert_type_pgp          1 /* recognized, but not supported */
+# define TLSEXT_cert_type_rpk          2
+# define TLSEXT_cert_type_1609dot2     3 /* recognized, but not supported */
+
 int SSL_CTX_set_tlsext_max_fragment_length(SSL_CTX *ctx, uint8_t mode);
 int SSL_set_tlsext_max_fragment_length(SSL *ssl, uint8_t mode);
 
index d7020f3b3a953c0cc29d3170a920d662f3a9f054..ac24145a03cc860bba53c00a3d884ffbd35b01dd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * {- join("\n * ", @autowarntext) -}
  *
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -314,6 +314,7 @@ X509_LOOKUP_ctrl_ex((x), X509_L_ADD_STORE, (name), 0, NULL,           \
 # define X509_V_ERR_CA_CERT_MISSING_KEY_USAGE            92
 # define X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3         93
 # define X509_V_ERR_EC_KEY_EXPLICIT_PARAMS               94
+# define X509_V_ERR_RPK_UNTRUSTED                        95
 
 /* Certificate verify flags */
 # ifndef OPENSSL_NO_DEPRECATED_1_1_0
@@ -468,11 +469,14 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
 void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
 int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *trust_store,
                         X509 *target, STACK_OF(X509) *untrusted);
+int X509_STORE_CTX_init_rpk(X509_STORE_CTX *ctx, X509_STORE *trust_store,
+                            EVP_PKEY* rpk);
 void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
 void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
 
 X509_STORE *X509_STORE_CTX_get0_store(const X509_STORE_CTX *ctx);
 X509 *X509_STORE_CTX_get0_cert(const X509_STORE_CTX *ctx);
+EVP_PKEY *X509_STORE_CTX_get0_rpk(const X509_STORE_CTX *ctx);
 STACK_OF(X509)* X509_STORE_CTX_get0_untrusted(const X509_STORE_CTX *ctx);
 void X509_STORE_CTX_set0_untrusted(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
 void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
@@ -665,6 +669,7 @@ X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(const X509_STORE_CTX *ctx);
 STACK_OF(X509) *X509_STORE_CTX_get0_chain(const X509_STORE_CTX *ctx);
 STACK_OF(X509) *X509_STORE_CTX_get1_chain(const X509_STORE_CTX *ctx);
 void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *target);
+void X509_STORE_CTX_set0_rpk(X509_STORE_CTX *ctx, EVP_PKEY *target);
 void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *c, STACK_OF(X509) *sk);
 void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk);
 int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
index 9336fb2cc93554cbc6ff469d62b40fe36639aaf6..9964a8c1eeb3849d5f8cf8ca5c364b6953f584e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright 2005 Nokia. All rights reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include "ssl_local.h"
 #include <openssl/asn1t.h>
+#include <openssl/encoder.h>
 #include <openssl/x509.h>
 
 typedef struct {
@@ -44,6 +45,7 @@ typedef struct {
     uint32_t tlsext_max_fragment_len_mode;
     ASN1_OCTET_STRING *ticket_appdata;
     uint32_t kex_group;
+    ASN1_OCTET_STRING *peer_rpk;
 } SSL_SESSION_ASN1;
 
 ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
@@ -75,7 +77,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
     ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16),
     ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 17),
     ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18),
-    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, kex_group, UINT32, 19)
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, kex_group, UINT32, 19),
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, peer_rpk, ASN1_OCTET_STRING, 20)
 } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
 
 IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
@@ -125,8 +128,10 @@ int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
 #endif
     ASN1_OCTET_STRING alpn_selected;
     ASN1_OCTET_STRING ticket_appdata;
+    ASN1_OCTET_STRING peer_rpk;
 
     long l;
+    int ret;
 
     if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
         return 0;
@@ -169,6 +174,14 @@ int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
 
     as.peer = in->peer;
 
+    as.peer_rpk = NULL;
+    peer_rpk.data = NULL;
+    if (in->peer_rpk != NULL) {
+        peer_rpk.length = i2d_PUBKEY(in->peer_rpk, &peer_rpk.data);
+        if (peer_rpk.length > 0 && peer_rpk.data != NULL)
+            as.peer_rpk = &peer_rpk;
+    }
+
     ssl_session_sinit(&as.tlsext_hostname, &tlsext_hostname,
                       in->ext.hostname);
     if (in->ext.tick) {
@@ -204,8 +217,9 @@ int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
         ssl_session_oinit(&as.ticket_appdata, &ticket_appdata,
                           in->ticket_appdata, in->ticket_appdata_len);
 
-    return i2d_SSL_SESSION_ASN1(&as, pp);
-
+    ret = i2d_SSL_SESSION_ASN1(&as, pp);
+    OPENSSL_free(peer_rpk.data);
+    return ret;
 }
 
 /* Utility functions for d2i_SSL_SESSION */
@@ -242,6 +256,12 @@ static int ssl_session_memcpy(unsigned char *dst, size_t *pdstlen,
 
 SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
                              long length)
+{
+    return d2i_SSL_SESSION_ex(a, pp, length, NULL, NULL);
+}
+SSL_SESSION *d2i_SSL_SESSION_ex(SSL_SESSION **a, const unsigned char **pp,
+                                long length, OSSL_LIB_CTX *libctx,
+                                const char *propq)
 {
     long id;
     size_t tmpl;
@@ -316,6 +336,19 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
     ret->peer = as->peer;
     as->peer = NULL;
 
+    EVP_PKEY_free(ret->peer_rpk);
+    ret->peer_rpk = NULL;
+    if (as->peer_rpk != NULL) {
+        const unsigned char *data = as->peer_rpk->data;
+
+        /*
+         * |data| is incremented; we don't want to lose original ptr
+         */
+        ret->peer_rpk = d2i_PUBKEY_ex(NULL, &data, as->peer_rpk->length, libctx, propq);
+        if (ret->peer_rpk == NULL)
+            goto err;
+    }
+
     if (!ssl_session_memcpy(ret->sid_ctx, &ret->sid_ctx_length,
                             as->session_id_context, SSL_MAX_SID_CTX_LENGTH))
         goto err;
index f35ec2ab680140fdf64d5e455d60098856216061..05bd3b9e99bc08311aa68f61d36042a7d826347e 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
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
@@ -414,13 +414,13 @@ void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg)
 }
 
 /*
- * Verify a certificate chain
+ * Verify a certificate chain/raw public key
  * Return codes:
  *  1: Verify success
  *  0: Verify failure or error
  * -1: Retry required
  */
-int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
+static int ssl_verify_internal(SSL_CONNECTION *s, STACK_OF(X509) *sk, EVP_PKEY *rpk)
 {
     X509 *x;
     int i = 0;
@@ -429,7 +429,12 @@ int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
     X509_VERIFY_PARAM *param;
     SSL_CTX *sctx;
 
-    if ((sk == NULL) || (sk_X509_num(sk) == 0))
+    /* Something must be passed in */
+    if ((sk == NULL || sk_X509_num(sk) == 0) && rpk == NULL)
+        return 0;
+
+    /* Only one can be set */
+    if (sk != NULL && rpk != NULL)
         return 0;
 
     sctx = SSL_CONNECTION_GET_CTX(s);
@@ -444,10 +449,17 @@ int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
         return 0;
     }
 
-    x = sk_X509_value(sk, 0);
-    if (!X509_STORE_CTX_init(ctx, verify_store, x, sk)) {
-        ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
-        goto end;
+    if (sk != NULL) {
+        x = sk_X509_value(sk, 0);
+        if (!X509_STORE_CTX_init(ctx, verify_store, x, sk)) {
+            ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
+            goto end;
+        }
+    } else {
+        if (!X509_STORE_CTX_init_rpk(ctx, verify_store, rpk)) {
+            ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
+            goto end;
+        }
     }
     param = X509_STORE_CTX_get0_param(ctx);
     /*
@@ -496,7 +508,8 @@ int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
     s->verify_result = X509_STORE_CTX_get_error(ctx);
     OSSL_STACK_OF_X509_free(s->verified_chain);
     s->verified_chain = NULL;
-    if (X509_STORE_CTX_get0_chain(ctx) != NULL) {
+
+    if (sk != NULL && X509_STORE_CTX_get0_chain(ctx) != NULL) {
         s->verified_chain = X509_STORE_CTX_get1_chain(ctx);
         if (s->verified_chain == NULL) {
             ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB);
@@ -512,6 +525,30 @@ int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
     return i;
 }
 
+/*
+ * Verify a raw public key
+ * Return codes:
+ *  1: Verify success
+ *  0: Verify failure or error
+ * -1: Retry required
+ */
+int ssl_verify_rpk(SSL_CONNECTION *s, EVP_PKEY *rpk)
+{
+    return ssl_verify_internal(s, NULL, rpk);
+}
+
+/*
+ * Verify a certificate chain
+ * Return codes:
+ *  1: Verify success
+ *  0: Verify failure or error
+ * -1: Retry required
+ */
+int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk)
+{
+    return ssl_verify_internal(s, sk, NULL);
+}
+
 static void set0_CA_list(STACK_OF(X509_NAME) **ca_list,
                         STACK_OF(X509_NAME) *name_list)
 {
index bec6733a00b3a9a89821847a406362bf32a21097..f1464f7d64fc5d116fb827e470447684d64fcafe 100644 (file)
@@ -23,6 +23,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     "attempt to reuse session in different context"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
     "at least (D)TLS 1.2 needed in Suite B mode"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CERTIFICATE), "bad certificate"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC),
     "bad change cipher spec"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
@@ -154,6 +155,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE),
     "ecdh required for suiteb mode"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EE_KEY_TOO_SMALL), "ee key too small"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_RAW_PUBLIC_KEY),
+    "empty raw public key"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),
     "empty srtp protection profile list"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ENCRYPTED_LENGTH_TOO_LONG),
@@ -218,6 +221,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     "invalid max early data"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_NULL_CMD_NAME),
     "invalid null cmd name"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_RAW_PUBLIC_KEY),
+    "invalid raw public key"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_RECORD), "invalid record"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SEQUENCE_NUMBER),
     "invalid sequence number"},
@@ -561,6 +566,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED),
     "wrong cipher returned"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_RPK_TYPE), "wrong rpk type"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH),
     "wrong signature length"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE),
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;
+}
index 87fb1fd7cfa1ca92de88323044dbdcd076e7be3b..89b29cb9a9c6e7e18b9932860e233537acfec7c6 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.
  *
 #define CERT_PRIVATE_KEY        2
 */
 
+/* Certificate Type State */
+# define OSSL_CERT_TYPE_CTOS_NONE    0
+# define OSSL_CERT_TYPE_CTOS_GOOD    1
+# define OSSL_CERT_TYPE_CTOS_ERROR   2
+
 /* Post-Handshake Authentication state */
 typedef enum {
     SSL_PHA_NONE = 0,
@@ -510,6 +515,8 @@ struct ssl_session_st {
      * to disable session caching and tickets.
      */
     int not_resumable;
+    /* Peer raw public key, if available */
+    EVP_PKEY *peer_rpk;
     /* This is the cert and type for the other end. */
     X509 *peer;
     /* Certificate chain peer sent. */
@@ -684,6 +691,8 @@ typedef enum tlsext_index_en {
     TLSEXT_IDX_extended_master_secret,
     TLSEXT_IDX_signature_algorithms_cert,
     TLSEXT_IDX_post_handshake_auth,
+    TLSEXT_IDX_client_cert_type,
+    TLSEXT_IDX_server_cert_type,
     TLSEXT_IDX_signature_algorithms,
     TLSEXT_IDX_supported_versions,
     TLSEXT_IDX_psk_kex_modes,
@@ -1170,6 +1179,12 @@ struct ssl_ctx_st {
     /* certificate compression preferences */
     int cert_comp_prefs[TLSEXT_comp_cert_limit];
 #endif
+
+    /* Certificate Type stuff - for RPK vs X.509 */
+    unsigned char *client_cert_type;
+    size_t client_cert_type_len;
+    unsigned char *server_cert_type;
+    size_t server_cert_type_len;
 };
 
 typedef struct cert_pkey_st CERT_PKEY;
@@ -1651,6 +1666,11 @@ struct ssl_connection_st {
         int compress_certificate_from_peer[TLSEXT_comp_cert_limit];
         /* indicate that we sent the extension, so we'll accept it */
         int compress_certificate_sent;
+
+        uint8_t client_cert_type;
+        uint8_t client_cert_type_ctos;
+        uint8_t server_cert_type;
+        uint8_t server_cert_type_ctos;
     } ext;
 
     /*
@@ -1771,6 +1791,12 @@ struct ssl_connection_st {
     /* certificate compression preferences */
     int cert_comp_prefs[TLSEXT_comp_cert_limit];
 #endif
+
+    /* Certificate Type stuff - for RPK vs X.509 */
+    unsigned char *client_cert_type;
+    size_t client_cert_type_len;
+    unsigned char *server_cert_type;
+    size_t server_cert_type_len;
 };
 
 # define SSL_CONNECTION_FROM_SSL_ONLY_int(ssl, c) \
@@ -2380,11 +2406,47 @@ struct openssl_ssl_test_functions {
 
 const char *ssl_protocol_to_string(int version);
 
+static ossl_inline int tls12_rpk_and_privkey(const SSL_CONNECTION *sc, int idx)
+{
+    /*
+     * This is to check for special cases when using RPK with just
+     * a private key, and NO CERTIFICATE
+     */
+    return ((sc->server && sc->ext.server_cert_type == TLSEXT_cert_type_rpk)
+            || (!sc->server && sc->ext.client_cert_type == TLSEXT_cert_type_rpk))
+        && sc->cert->pkeys[idx].privatekey != NULL
+        && sc->cert->pkeys[idx].x509 == NULL;
+}
+
+static ossl_inline int ssl_has_cert_type(const SSL_CONNECTION *sc, unsigned char ct)
+{
+    unsigned char *ptr;
+    size_t len;
+
+    if (sc->server) {
+        ptr = sc->server_cert_type;
+        len = sc->server_cert_type_len;
+    } else {
+        ptr = sc->client_cert_type;
+        len = sc->client_cert_type_len;
+    }
+
+    if (ptr == NULL)
+        return 0;
+
+    return memchr(ptr, ct, len) != NULL;
+}
+
 /* Returns true if certificate and private key for 'idx' are present */
 static ossl_inline int ssl_has_cert(const SSL_CONNECTION *s, int idx)
 {
     if (idx < 0 || idx >= (int)s->ssl_pkey_num)
         return 0;
+
+    /* If RPK is enabled for this SSL... only require private key */
+    if (ssl_has_cert_type(s, TLSEXT_cert_type_rpk))
+        return s->cert->pkeys[idx].privatekey != NULL;
+
     return s->cert->pkeys[idx].x509 != NULL
         && s->cert->pkeys[idx].privatekey != NULL;
 }
@@ -2461,6 +2523,7 @@ __owur int ssl_cert_set_current(CERT *c, long arg);
 void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg);
 
 __owur int ssl_verify_cert_chain(SSL_CONNECTION *s, STACK_OF(X509) *sk);
+__owur int ssl_verify_rpk(SSL_CONNECTION *s, EVP_PKEY *rpk);
 __owur int ssl_build_cert_chain(SSL_CONNECTION *s, SSL_CTX *ctx, int flags);
 __owur int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain,
                                    int ref);
index 250e4dfb832c4506c94c26a70b34e8e225808036..28d6cc1f154355205fc9fb90fb118740502dfd27 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 2005 Nokia. All rights reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
@@ -165,6 +165,7 @@ SSL_SESSION *ssl_session_dup(const SSL_SESSION *src, int ticket)
 #endif
     dest->peer_chain = NULL;
     dest->peer = NULL;
+    dest->peer_rpk = NULL;
     dest->ticket_appdata = NULL;
     memset(&dest->ex_data, 0, sizeof(dest->ex_data));
 
@@ -200,6 +201,13 @@ SSL_SESSION *ssl_session_dup(const SSL_SESSION *src, int ticket)
             goto err;
         }
     }
+
+    if (src->peer_rpk != NULL) {
+        if (!EVP_PKEY_up_ref(src->peer_rpk))
+            goto err;
+        dest->peer_rpk = src->peer_rpk;
+    }
+
 #ifndef OPENSSL_NO_PSK
     if (src->psk_identity_hint) {
         dest->psk_identity_hint = OPENSSL_strdup(src->psk_identity_hint);
@@ -823,6 +831,7 @@ void SSL_SESSION_free(SSL_SESSION *ss)
     OPENSSL_cleanse(ss->master_key, sizeof(ss->master_key));
     OPENSSL_cleanse(ss->session_id, sizeof(ss->session_id));
     X509_free(ss->peer);
+    EVP_PKEY_free(ss->peer_rpk);
     OSSL_STACK_OF_X509_free(ss->peer_chain);
     OPENSSL_free(ss->ext.hostname);
     OPENSSL_free(ss->ext.tick);
@@ -1042,6 +1051,11 @@ X509 *SSL_SESSION_get0_peer(SSL_SESSION *s)
     return s->peer;
 }
 
+EVP_PKEY *SSL_SESSION_get0_peer_rpk(SSL_SESSION *s)
+{
+    return s->peer_rpk;
+}
+
 int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx,
                                 unsigned int sid_ctx_len)
 {
index d164719476719a72ddab0485f29cbe67078b1f2f..3bb7c4af2625beabb3a9844bdd0ba16051947684 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -34,6 +34,8 @@ static int init_alpn(SSL_CONNECTION *s, unsigned int context);
 static int final_alpn(SSL_CONNECTION *s, unsigned int context, int sent);
 static int init_sig_algs_cert(SSL_CONNECTION *s, unsigned int context);
 static int init_sig_algs(SSL_CONNECTION *s, unsigned int context);
+static int init_server_cert_type(SSL_CONNECTION *sc, unsigned int context);
+static int init_client_cert_type(SSL_CONNECTION *sc, unsigned int context);
 static int init_certificate_authorities(SSL_CONNECTION *s,
                                         unsigned int context);
 static EXT_RETURN tls_construct_certificate_authorities(SSL_CONNECTION *s,
@@ -309,6 +311,24 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         NULL, tls_construct_ctos_post_handshake_auth,
         NULL,
     },
+    {
+        TLSEXT_TYPE_client_cert_type,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
+        init_client_cert_type,
+        tls_parse_ctos_client_cert_type, tls_parse_stoc_client_cert_type,
+        tls_construct_stoc_client_cert_type, tls_construct_ctos_client_cert_type,
+        NULL
+    },
+    {
+        TLSEXT_TYPE_server_cert_type,
+        SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | SSL_EXT_TLS1_2_SERVER_HELLO,
+        init_server_cert_type,
+        tls_parse_ctos_server_cert_type, tls_parse_stoc_server_cert_type,
+        tls_construct_stoc_server_cert_type, tls_construct_ctos_server_cert_type,
+        NULL
+    },
     {
         TLSEXT_TYPE_signature_algorithms,
         SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_CERTIFICATE_REQUEST,
@@ -1779,6 +1799,18 @@ static EXT_RETURN tls_construct_compress_certificate(SSL_CONNECTION *sc, WPACKET
     if (!ossl_comp_has_alg(0))
         return EXT_RETURN_NOT_SENT;
 
+    /* Server: Don't attempt to compress a non-X509 (i.e. an RPK) */
+    if (sc->server && sc->ext.server_cert_type != TLSEXT_cert_type_x509) {
+        sc->cert_comp_prefs[0] = TLSEXT_comp_cert_none;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    /* Client: If we sent a client cert-type extension, don't indicate compression */
+    if (!sc->server && sc->ext.client_cert_type_ctos) {
+        sc->cert_comp_prefs[0] = TLSEXT_comp_cert_none;
+        return EXT_RETURN_NOT_SENT;
+    }
+
     /* Do not indicate we support receiving compressed certificates */
     if ((sc->options & SSL_OP_NO_RX_CERTIFICATE_COMPRESSION) != 0)
         return EXT_RETURN_NOT_SENT;
@@ -1843,6 +1875,12 @@ int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt, unsigned int
     if (!ossl_comp_has_alg(0))
         return 1;
 
+    /* Don't attempt to compress a non-X509 (i.e. an RPK) */
+    if (sc->server && sc->ext.server_cert_type != TLSEXT_cert_type_x509)
+        return 1;
+    if (!sc->server && sc->ext.client_cert_type != TLSEXT_cert_type_x509)
+        return 1;
+
     /* Ignore the extension and don't send compressed certificates */
     if ((sc->options & SSL_OP_NO_TX_CERTIFICATE_COMPRESSION) != 0)
         return 1;
@@ -1869,3 +1907,23 @@ int tls_parse_compress_certificate(SSL_CONNECTION *sc, PACKET *pkt, unsigned int
 #endif
     return 1;
 }
+
+static int init_server_cert_type(SSL_CONNECTION *sc, unsigned int context)
+{
+    /* Only reset when parsing client hello */
+    if (sc->server) {
+        sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.server_cert_type = TLSEXT_cert_type_x509;
+    }
+    return 1;
+}
+
+static int init_client_cert_type(SSL_CONNECTION *sc, unsigned int context)
+{
+    /* Only reset when parsing client hello */
+    if (sc->server) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.client_cert_type = TLSEXT_cert_type_x509;
+    }
+    return 1;
+}
index de71363fc1ed091644774bb4af4a00615f776ae2..d32dcfbd069afbfde0e2c35d42037e8bf0d8a65f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -2015,3 +2015,107 @@ int tls_parse_stoc_psk(SSL_CONNECTION *s, PACKET *pkt,
 
     return 1;
 }
+
+EXT_RETURN tls_construct_ctos_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx)
+{
+    sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+    if (sc->client_cert_type == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_client_cert_type)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, sc->client_cert_type, sc->client_cert_type_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_GOOD;
+    return EXT_RETURN_SENT;
+}
+
+int tls_parse_stoc_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx)
+{
+    unsigned int type;
+
+    if (PACKET_remaining(pkt) != 1) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!PACKET_get_1(pkt, &type)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* We did not send/ask for this */
+    if (!ossl_assert(sc->ext.client_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* We don't have this enabled */
+    if (sc->client_cert_type == NULL) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* Given back a value we didn't configure */
+    if (memchr(sc->client_cert_type, type, sc->client_cert_type_len) == NULL) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_VALUE);
+        return 0;
+    }
+    sc->ext.client_cert_type = type;
+    return 1;
+}
+
+EXT_RETURN tls_construct_ctos_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx)
+{
+    sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+    if (sc->server_cert_type == NULL)
+        return EXT_RETURN_NOT_SENT;
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_cert_type)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_sub_memcpy_u8(pkt, sc->server_cert_type, sc->server_cert_type_len)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_GOOD;
+    return EXT_RETURN_SENT;
+}
+
+int tls_parse_stoc_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx)
+{
+    unsigned int type;
+
+    if (PACKET_remaining(pkt) != 1) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!PACKET_get_1(pkt, &type)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* We did not send/ask for this */
+    if (!ossl_assert(sc->ext.server_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* We don't have this enabled */
+    if (sc->server_cert_type == NULL) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* Given back a value we didn't configure */
+    if (memchr(sc->server_cert_type, type, sc->server_cert_type_len) == NULL) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_VALUE);
+        return 0;
+    }
+    sc->ext.server_cert_type = type;
+    return 1;
+}
index 83470b1bf334873d7a1c09f5c78638c3037e5c1f..81f20b5f6bd0487ff0cfcb5c1059ba6cfc6498cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2014-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -193,6 +193,7 @@ int custom_ext_add(SSL_CONNECTION *s, int context, WPACKET *pkt, X509 *x,
                         | SSL_EXT_TLS1_3_SERVER_HELLO
                         | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
                         | SSL_EXT_TLS1_3_CERTIFICATE
+                        | SSL_EXT_TLS1_3_RAW_PUBLIC_KEY
                         | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST)) != 0) {
             /* Only send extensions present in ClientHello/CertificateRequest */
             if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
@@ -534,6 +535,8 @@ int SSL_extension_supported(unsigned int ext_type)
     case TLSEXT_TYPE_psk:
     case TLSEXT_TYPE_post_handshake_auth:
     case TLSEXT_TYPE_compress_certificate:
+    case TLSEXT_TYPE_client_cert_type:
+    case TLSEXT_TYPE_server_cert_type:
         return 1;
     default:
         return 0;
index ff1f2a77e06a6eecead5c0a0017ad55977fe4e58..621df5e2f5ec4c084cc6b92a536bfbaaa45ced24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -1948,3 +1948,164 @@ EXT_RETURN tls_construct_stoc_psk(SSL_CONNECTION *s, WPACKET *pkt,
 
     return EXT_RETURN_SENT;
 }
+
+EXT_RETURN tls_construct_stoc_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx)
+{
+    if (sc->ext.client_cert_type_ctos == OSSL_CERT_TYPE_CTOS_ERROR
+        && (send_certificate_request(sc)
+            || sc->post_handshake_auth == SSL_PHA_EXT_RECEIVED)) {
+        /* Did not receive an acceptable cert type - and doing client auth */
+        SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION);
+        return EXT_RETURN_FAIL;
+    }
+
+    if (sc->ext.client_cert_type == TLSEXT_cert_type_x509) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    /*
+     * Note: only supposed to send this if we are going to do a cert request,
+     * but TLSv1.3 could do a PHA request if the client supports it
+     */
+    if ((!send_certificate_request(sc) && sc->post_handshake_auth != SSL_PHA_EXT_RECEIVED)
+            || sc->ext.client_cert_type_ctos != OSSL_CERT_TYPE_CTOS_GOOD
+            || sc->client_cert_type == NULL) {
+        /* if we don't send it, reset to TLSEXT_cert_type_x509 */
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.client_cert_type = TLSEXT_cert_type_x509;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_client_cert_type)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, sc->ext.client_cert_type)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    return EXT_RETURN_SENT;
+}
+
+/* One of |pref|, |other| is configured and the values are sanitized */
+static int reconcile_cert_type(const unsigned char *pref, size_t pref_len,
+                               const unsigned char *other, size_t other_len,
+                               uint8_t *chosen_cert_type)
+{
+    size_t i;
+
+    for (i = 0; i < pref_len; i++) {
+        if (memchr(other, pref[i], other_len) != NULL) {
+            *chosen_cert_type = pref[i];
+            return OSSL_CERT_TYPE_CTOS_GOOD;
+        }
+    }
+    return OSSL_CERT_TYPE_CTOS_ERROR;
+}
+
+int tls_parse_ctos_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx)
+{
+    PACKET supported_cert_types;
+    const unsigned char *data;
+    size_t len;
+
+    /* Ignore the extension */
+    if (sc->client_cert_type == NULL) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.client_cert_type = TLSEXT_cert_type_x509;
+        return 1;
+    }
+
+    if (!PACKET_as_length_prefixed_1(pkt, &supported_cert_types)) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR;
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if ((len = PACKET_remaining(&supported_cert_types)) == 0) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR;
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!PACKET_get_bytes(&supported_cert_types, &data, len)) {
+        sc->ext.client_cert_type_ctos = OSSL_CERT_TYPE_CTOS_ERROR;
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* client_cert_type: client (peer) has priority */
+    sc->ext.client_cert_type_ctos = reconcile_cert_type(data, len,
+                                                        sc->client_cert_type, sc->client_cert_type_len,
+                                                        &sc->ext.client_cert_type);
+
+    /* Ignore the error until sending - so we can check cert auth*/
+    return 1;
+}
+
+EXT_RETURN tls_construct_stoc_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx)
+{
+    if (sc->ext.server_cert_type == TLSEXT_cert_type_x509) {
+        sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        return EXT_RETURN_NOT_SENT;
+    }
+    if (sc->ext.server_cert_type_ctos != OSSL_CERT_TYPE_CTOS_GOOD
+            || sc->server_cert_type == NULL) {
+        /* if we don't send it, reset to TLSEXT_cert_type_x509 */
+        sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.server_cert_type = TLSEXT_cert_type_x509;
+        return EXT_RETURN_NOT_SENT;
+    }
+
+    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_cert_type)
+            || !WPACKET_start_sub_packet_u16(pkt)
+            || !WPACKET_put_bytes_u8(pkt, sc->ext.server_cert_type)
+            || !WPACKET_close(pkt)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return EXT_RETURN_FAIL;
+    }
+    return EXT_RETURN_SENT;
+}
+
+int tls_parse_ctos_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx)
+{
+    PACKET supported_cert_types;
+    const unsigned char *data;
+    size_t len;
+
+    /* Ignore the extension */
+    if (sc->server_cert_type == NULL) {
+        sc->ext.server_cert_type_ctos = OSSL_CERT_TYPE_CTOS_NONE;
+        sc->ext.server_cert_type = TLSEXT_cert_type_x509;
+        return 1;
+    }
+
+    if (!PACKET_as_length_prefixed_1(pkt, &supported_cert_types)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if ((len = PACKET_remaining(&supported_cert_types)) == 0) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    if (!PACKET_get_bytes(&supported_cert_types, &data, len)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+    /* server_cert_type: server (this) has priority */
+    sc->ext.server_cert_type_ctos = reconcile_cert_type(sc->server_cert_type, sc->server_cert_type_len,
+                                                        data, len,
+                                                        &sc->ext.server_cert_type);
+    if (sc->ext.server_cert_type_ctos == OSSL_CERT_TYPE_CTOS_GOOD)
+        return 1;
+
+    /* Did not receive an acceptable cert type */
+    SSLfatal(sc, SSL_AD_UNSUPPORTED_CERTIFICATE, SSL_R_BAD_EXTENSION);
+    return 0;
+}
index 8d90520d14ab9d4a647fcc40e56230c9b93e0d0a..1e3331941301bb549bf69c9ec6f7fecd3357baed 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.
  *
@@ -38,6 +38,11 @@ static int key_exchange_expected(SSL_CONNECTION *s);
 static int ssl_cipher_list_to_bytes(SSL_CONNECTION *s, STACK_OF(SSL_CIPHER) *sk,
                                     WPACKET *pkt);
 
+static ossl_inline int received_server_cert(SSL_CONNECTION *sc)
+{
+    return sc->session->peer_rpk != NULL || sc->session->peer != NULL;
+}
+
 /*
  * Is a CertificateRequest message allowed at the moment or not?
  *
@@ -419,6 +424,13 @@ int ossl_statem_client_read_transition(SSL_CONNECTION *s, int mt)
     return 0;
 }
 
+static int do_compressed_cert(SSL_CONNECTION *sc)
+{
+    /* If we negotiated RPK, we won't try to compress it */
+    return sc->ext.client_cert_type == TLSEXT_cert_type_x509
+        && sc->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none;
+}
+
 /*
  * ossl_statem_client13_write_transition() works out what handshake state to
  * move to next when the TLSv1.3 client is writing messages to be sent to the
@@ -441,7 +453,7 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
 
     case TLS_ST_CR_CERT_REQ:
         if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
-            if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
+            if (do_compressed_cert(s))
                 st->hand_state = TLS_ST_CW_COMP_CERT;
             else
                 st->hand_state = TLS_ST_CW_CERT;
@@ -468,7 +480,7 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
             st->hand_state = TLS_ST_CW_CHANGE;
         else if (s->s3.tmp.cert_req == 0)
             st->hand_state = TLS_ST_CW_FINISHED;
-        else if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
+        else if (do_compressed_cert(s))
             st->hand_state = TLS_ST_CW_COMP_CERT;
         else
             st->hand_state = TLS_ST_CW_CERT;
@@ -485,7 +497,7 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
     case TLS_ST_CW_CHANGE:
         if (s->s3.tmp.cert_req == 0)
             st->hand_state = TLS_ST_CW_FINISHED;
-        else if (s->ext.compress_certificate_from_peer[0] != TLSEXT_comp_cert_none)
+        else if (do_compressed_cert(s))
             st->hand_state = TLS_ST_CW_COMP_CERT;
         else
             st->hand_state = TLS_ST_CW_CERT;
@@ -1849,6 +1861,81 @@ static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL_CONNECTION *s,
     return MSG_PROCESS_ERROR;
 }
 
+MSG_PROCESS_RETURN tls_process_server_rpk(SSL_CONNECTION *sc, PACKET *pkt)
+{
+    EVP_PKEY *peer_rpk;
+
+    if (!tls_process_rpk(sc, pkt, &peer_rpk)) {
+        /* SSLfatal() already called */
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (peer_rpk == NULL) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_CERTIFICATE);
+        return MSG_PROCESS_ERROR;
+    }
+
+    EVP_PKEY_free(sc->session->peer_rpk);
+    sc->session->peer_rpk = peer_rpk;
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+}
+
+static WORK_STATE tls_post_process_server_rpk(SSL_CONNECTION *sc,
+                                              WORK_STATE wst)
+{
+    size_t certidx;
+    const SSL_CERT_LOOKUP *clu;
+
+    if (sc->session->peer_rpk == NULL) {
+        SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER,
+                 SSL_R_INVALID_RAW_PUBLIC_KEY);
+        return WORK_ERROR;
+    }
+
+    if (sc->rwstate == SSL_RETRY_VERIFY)
+        sc->rwstate = SSL_NOTHING;
+    if (ssl_verify_rpk(sc, sc->session->peer_rpk) > 0
+            && sc->rwstate == SSL_RETRY_VERIFY)
+        return WORK_MORE_A;
+
+    if ((clu = ssl_cert_lookup_by_pkey(sc->session->peer_rpk, &certidx,
+                                       SSL_CONNECTION_GET_CTX(sc))) == NULL) {
+        SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return WORK_ERROR;
+    }
+
+    /*
+     * Check certificate type is consistent with ciphersuite. For TLS 1.3
+     * skip check since TLS 1.3 ciphersuites can be used with any certificate
+     * type.
+     */
+    if (!SSL_CONNECTION_IS_TLS13(sc)) {
+        if ((clu->amask & sc->s3.tmp.new_cipher->algorithm_auth) == 0) {
+            SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_WRONG_RPK_TYPE);
+            return WORK_ERROR;
+        }
+    }
+
+    /* Ensure there is no peer/peer_chain */
+    X509_free(sc->session->peer);
+    sc->session->peer = NULL;
+    sk_X509_pop_free(sc->session->peer_chain, X509_free);
+    sc->session->peer_chain = NULL;
+    sc->session->verify_result = sc->verify_result;
+
+    /* Save the current hash state for when we receive the CertificateVerify */
+    if (SSL_CONNECTION_IS_TLS13(sc)
+            && !ssl_handshake_hash(sc, sc->cert_verify_hash,
+                                   sizeof(sc->cert_verify_hash),
+                                   &sc->cert_verify_hash_len)) {
+        /* SSLfatal() already called */
+        return WORK_ERROR;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
 /* prepare server cert verification by setting s->session->peer_chain from pkt */
 MSG_PROCESS_RETURN tls_process_server_certificate(SSL_CONNECTION *s,
                                                   PACKET *pkt)
@@ -1860,6 +1947,14 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL_CONNECTION *s,
     unsigned int context = 0;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
 
+    if (s->ext.server_cert_type == TLSEXT_cert_type_rpk)
+        return tls_process_server_rpk(s, pkt);
+    if (s->ext.server_cert_type != TLSEXT_cert_type_x509) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_CERTIFICATE,
+                 SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        goto err;
+    }
+
     if ((s->session->peer_chain = sk_X509_new_null()) == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
         goto err;
@@ -1947,6 +2042,9 @@ WORK_STATE tls_post_process_server_certificate(SSL_CONNECTION *s,
     size_t certidx;
     int i;
 
+    if (s->ext.server_cert_type == TLSEXT_cert_type_rpk)
+        return tls_post_process_server_rpk(s, wst);
+
     if (s->rwstate == SSL_RETRY_VERIFY)
         s->rwstate = SSL_NOTHING;
     i = ssl_verify_cert_chain(s, s->session->peer_chain);
@@ -2009,6 +2107,9 @@ WORK_STATE tls_post_process_server_certificate(SSL_CONNECTION *s,
     X509_up_ref(x);
     s->session->peer = x;
     s->session->verify_result = s->verify_result;
+    /* Ensure there is no RPK */
+    EVP_PKEY_free(s->session->peer_rpk);
+    s->session->peer_rpk = NULL;
 
     /* Save the current hash state for when we receive the CertificateVerify */
     if (SSL_CONNECTION_IS_TLS13(s)
@@ -2111,7 +2212,7 @@ static int tls_process_ske_srp(SSL_CONNECTION *s, PACKET *pkt, EVP_PKEY **pkey)
 
     /* We must check if there is a certificate */
     if (s->s3.tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS))
-        *pkey = X509_get0_pubkey(s->session->peer);
+        *pkey = tls_get_peer_pkey(s);
 
     return 1;
 #else
@@ -2200,7 +2301,7 @@ static int tls_process_ske_dhe(SSL_CONNECTION *s, PACKET *pkt, EVP_PKEY **pkey)
      * public keys. We should have a less ad-hoc way of doing this
      */
     if (s->s3.tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS))
-        *pkey = X509_get0_pubkey(s->session->peer);
+        *pkey = tls_get_peer_pkey(s);
     /* else anonymous DH, so no certificate or pkey. */
 
     ret = 1;
@@ -2265,9 +2366,9 @@ static int tls_process_ske_ecdhe(SSL_CONNECTION *s, PACKET *pkt, EVP_PKEY **pkey
      * and ECDSA.
      */
     if (s->s3.tmp.new_cipher->algorithm_auth & SSL_aECDSA)
-        *pkey = X509_get0_pubkey(s->session->peer);
+        *pkey = tls_get_peer_pkey(s);
     else if (s->s3.tmp.new_cipher->algorithm_auth & SSL_aRSA)
-        *pkey = X509_get0_pubkey(s->session->peer);
+        *pkey = tls_get_peer_pkey(s);
     /* else anonymous ECDH, so no certificate or pkey. */
 
     /* Cache the agreed upon group in the SSL_SESSION */
@@ -2945,7 +3046,7 @@ static int tls_construct_cke_rsa(SSL_CONNECTION *s, WPACKET *pkt)
     size_t pmslen = 0;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
 
-    if (s->session->peer == NULL) {
+    if (!received_server_cert(s)) {
         /*
          * We should always have a server certificate with SSL_kRSA.
          */
@@ -2953,7 +3054,11 @@ static int tls_construct_cke_rsa(SSL_CONNECTION *s, WPACKET *pkt)
         return 0;
     }
 
-    pkey = X509_get0_pubkey(s->session->peer);
+    if ((pkey = tls_get_peer_pkey(s)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
     if (!EVP_PKEY_is_a(pkey, "RSA")) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return 0;
@@ -3128,7 +3233,7 @@ static int tls_construct_cke_gost(SSL_CONNECTION *s, WPACKET *pkt)
 #ifndef OPENSSL_NO_GOST
     /* GOST key exchange message creation */
     EVP_PKEY_CTX *pkey_ctx = NULL;
-    X509 *peer_cert;
+    EVP_PKEY *pkey = NULL;
     size_t msglen;
     unsigned int md_len;
     unsigned char shared_ukm[32], tmp[256];
@@ -3144,15 +3249,14 @@ static int tls_construct_cke_gost(SSL_CONNECTION *s, WPACKET *pkt)
     /*
      * Get server certificate PKEY and create ctx from it
      */
-    peer_cert = s->session->peer;
-    if (peer_cert == NULL) {
+    if ((pkey = tls_get_peer_pkey(s)) == NULL) {
         SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                  SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
         return 0;
     }
 
     pkey_ctx = EVP_PKEY_CTX_new_from_pkey(sctx->libctx,
-                                          X509_get0_pubkey(peer_cert),
+                                          pkey,
                                           sctx->propq);
     if (pkey_ctx == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
@@ -3279,7 +3383,7 @@ static int tls_construct_cke_gost18(SSL_CONNECTION *s, WPACKET *pkt)
     unsigned char rnd_dgst[32];
     unsigned char *encdata = NULL;
     EVP_PKEY_CTX *pkey_ctx = NULL;
-    X509 *peer_cert;
+    EVP_PKEY *pkey;
     unsigned char *pms = NULL;
     size_t pmslen = 0;
     size_t msglen;
@@ -3310,15 +3414,14 @@ static int tls_construct_cke_gost18(SSL_CONNECTION *s, WPACKET *pkt)
     }
 
      /* Get server certificate PKEY and create ctx from it */
-    peer_cert = s->session->peer;
-    if (peer_cert == NULL) {
+    if ((pkey = tls_get_peer_pkey(s)) == NULL) {
         SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                  SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
         goto err;
     }
 
     pkey_ctx = EVP_PKEY_CTX_new_from_pkey(sctx->libctx,
-                                          X509_get0_pubkey(peer_cert),
+                                          pkey,
                                           sctx->propq);
     if (pkey_ctx == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
@@ -3629,6 +3732,7 @@ WORK_STATE tls_prepare_client_certificate(SSL_CONNECTION *s, WORK_STATE wst)
 CON_FUNC_RETURN tls_construct_client_certificate(SSL_CONNECTION *s,
                                                  WPACKET *pkt)
 {
+    CERT_PKEY *cpk = NULL;
     SSL *ssl = SSL_CONNECTION_GET_SSL(s);
 
     if (SSL_CONNECTION_IS_TLS13(s)) {
@@ -3643,10 +3747,23 @@ CON_FUNC_RETURN tls_construct_client_certificate(SSL_CONNECTION *s,
             return CON_FUNC_ERROR;
         }
     }
-    if (!ssl3_output_cert_chain(s, pkt,
-                                (s->s3.tmp.cert_req == 2) ? NULL
-                                                           : s->cert->key, 0)) {
-        /* SSLfatal() already called */
+    if (s->s3.tmp.cert_req != 2)
+        cpk = s->cert->key;
+    switch (s->ext.client_cert_type) {
+    case TLSEXT_cert_type_rpk:
+        if (!tls_output_rpk(s, pkt, cpk)) {
+            /* SSLfatal() already called */
+            return CON_FUNC_ERROR;
+        }
+        break;
+    case TLSEXT_cert_type_x509:
+        if (!ssl3_output_cert_chain(s, pkt, cpk, 0)) {
+            /* SSLfatal() already called */
+            return CON_FUNC_ERROR;
+        }
+        break;
+    default:
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return CON_FUNC_ERROR;
     }
 
@@ -3764,6 +3881,7 @@ int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s)
     const SSL_CERT_LOOKUP *clu;
     size_t idx;
     long alg_k, alg_a;
+    EVP_PKEY *pkey;
 
     alg_k = s->s3.tmp.new_cipher->algorithm_mkey;
     alg_a = s->s3.tmp.new_cipher->algorithm_auth;
@@ -3773,8 +3891,8 @@ int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s)
         return 1;
 
     /* This is the passed certificate */
-    clu = ssl_cert_lookup_by_pkey(X509_get0_pubkey(s->session->peer), &idx,
-                  SSL_CONNECTION_GET_CTX(s));
+    pkey = tls_get_peer_pkey(s);
+    clu = ssl_cert_lookup_by_pkey(pkey, &idx, SSL_CONNECTION_GET_CTX(s));
 
     /* Check certificate is recognised and suitable for cipher */
     if (clu == NULL || (alg_a & clu->amask) == 0) {
@@ -3782,13 +3900,6 @@ int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s)
         return 0;
     }
 
-    if (clu->amask & SSL_aECDSA) {
-        if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s))
-            return 1;
-        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_ECC_CERT);
-        return 0;
-    }
-
     if (alg_k & (SSL_kRSA | SSL_kRSAPSK) && idx != SSL_PKEY_RSA) {
         SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                  SSL_R_MISSING_RSA_ENCRYPTING_CERT);
@@ -3800,6 +3911,17 @@ int ssl3_check_cert_and_algorithm(SSL_CONNECTION *s)
         return 0;
     }
 
+    /* Early out to skip the checks below */
+    if (s->session->peer_rpk != NULL)
+        return 1;
+
+    if (clu->amask & SSL_aECDSA) {
+        if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s))
+            return 1;
+        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_BAD_ECC_CERT);
+        return 0;
+    }
+
     return 1;
 }
 
index 1bc01e1d25594979878b73812c81d2fd5120de92..4b498cd76f82219f238c72a263c6d40088f5181f 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
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
@@ -20,6 +20,7 @@
 #include <openssl/rsa.h>
 #include <openssl/x509.h>
 #include <openssl/trace.h>
+#include <openssl/encoder.h>
 
 /*
  * Map error codes to TLS/SSL alart types.
@@ -447,7 +448,6 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt)
     MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
     int j;
     unsigned int len;
-    X509 *peer;
     const EVP_MD *md = NULL;
     size_t hdatalen = 0;
     void *hdata;
@@ -461,8 +461,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt)
         goto err;
     }
 
-    peer = s->session->peer;
-    pkey = X509_get0_pubkey(peer);
+    pkey = tls_get_peer_pkey(s);
     if (pkey == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
@@ -1092,6 +1091,291 @@ static int ssl_add_cert_chain(SSL_CONNECTION *s, WPACKET *pkt, CERT_PKEY *cpk, i
     return 1;
 }
 
+EVP_PKEY* tls_get_peer_pkey(const SSL_CONNECTION *sc)
+{
+    if (sc->session->peer_rpk != NULL)
+        return sc->session->peer_rpk;
+    if (sc->session->peer != NULL)
+        return X509_get0_pubkey(sc->session->peer);
+    return NULL;
+}
+
+int tls_process_rpk(SSL_CONNECTION *sc, PACKET *pkt, EVP_PKEY **peer_rpk)
+{
+    EVP_PKEY *pkey = NULL;
+    int ret = 0;
+    RAW_EXTENSION *rawexts = NULL;
+    PACKET extensions;
+    PACKET context;
+    unsigned long cert_len = 0, spki_len = 0;
+    const unsigned char *spki, *spkistart;
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(sc);
+
+    /*-
+     * ----------------------------
+     * TLS 1.3 Certificate message:
+     * ----------------------------
+     * https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2
+     *
+     *   enum {
+     *       X509(0),
+     *       RawPublicKey(2),
+     *       (255)
+     *   } CertificateType;
+     *
+     *   struct {
+     *       select (certificate_type) {
+     *           case RawPublicKey:
+     *             // From RFC 7250 ASN.1_subjectPublicKeyInfo
+     *             opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
+     *
+     *           case X509:
+     *             opaque cert_data<1..2^24-1>;
+     *       };
+     *       Extension extensions<0..2^16-1>;
+     *   } CertificateEntry;
+     *
+     *   struct {
+     *       opaque certificate_request_context<0..2^8-1>;
+     *       CertificateEntry certificate_list<0..2^24-1>;
+     *   } Certificate;
+     *
+     * The client MUST send a Certificate message if and only if the server
+     * has requested client authentication via a CertificateRequest message
+     * (Section 4.3.2).  If the server requests client authentication but no
+     * suitable certificate is available, the client MUST send a Certificate
+     * message containing no certificates (i.e., with the "certificate_list"
+     * field having length 0).
+     *
+     * ----------------------------
+     * TLS 1.2 Certificate message:
+     * ----------------------------
+     * https://datatracker.ietf.org/doc/html/rfc7250#section-3
+     *
+     *   opaque ASN.1Cert<1..2^24-1>;
+     *
+     *   struct {
+     *       select(certificate_type){
+     *
+     *            // certificate type defined in this document.
+     *            case RawPublicKey:
+     *              opaque ASN.1_subjectPublicKeyInfo<1..2^24-1>;
+     *
+     *           // X.509 certificate defined in RFC 5246
+     *           case X.509:
+     *             ASN.1Cert certificate_list<0..2^24-1>;
+     *
+     *           // Additional certificate type based on
+     *           // "TLS Certificate Types" subregistry
+     *       };
+     *   } Certificate;
+     *
+     * -------------
+     * Consequently:
+     * -------------
+     * After the (TLS 1.3 only) context octet string (1 byte length + data) the
+     * Certificate message has a 3-byte length that is zero in the client to
+     * server message when the client has no RPK to send.  In that case, there
+     * are no (TLS 1.3 only) per-certificate extensions either, because the
+     * [CertificateEntry] list is empty.
+     *
+     * In the server to client direction, or when the client had an RPK to send,
+     * the TLS 1.3 message just prepends the length of the RPK+extensions,
+     * while TLS <= 1.2 sends just the RPK (octet-string).
+     *
+     * The context must be zero-length in the server to client direction, and
+     * must match the value recorded in the certificate request in the client
+     * to server direction.
+     */
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        if (!PACKET_get_length_prefixed_1(pkt, &context)) {
+            SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_INVALID_CONTEXT);
+            goto err;
+        }
+        if (sc->server) {
+            if (sc->pha_context == NULL) {
+                if (PACKET_remaining(&context) != 0) {
+                    SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_INVALID_CONTEXT);
+                    goto err;
+                }
+            } else {
+                if (!PACKET_equal(&context, sc->pha_context, sc->pha_context_len)) {
+                    SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_INVALID_CONTEXT);
+                    goto err;
+                }
+            }
+        } else {
+            if (PACKET_remaining(&context) != 0) {
+                SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_INVALID_CONTEXT);
+                goto err;
+            }
+        }
+    }
+
+    if (!PACKET_get_net_3(pkt, &cert_len)
+        || PACKET_remaining(pkt) != cert_len) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /*
+     * The list length may be zero when there is no RPK.  In the case of TLS
+     * 1.2 this is actually the RPK length, which cannot be zero as specified,
+     * but that breaks the ability of the client to decline client auth. We
+     * overload the 0 RPK length to mean "no RPK".  This interpretation is
+     * also used some other (reference?) implementations, but is not supported
+     * by the verbatim RFC7250 text.
+     */
+    if (cert_len == 0)
+        return 1;
+
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        /*
+         * With TLS 1.3, a non-empty explicit-length RPK octet-string followed
+         * by a possibly empty extension block.
+         */
+        if (!PACKET_get_net_3(pkt, &spki_len)) {
+            SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+        if (spki_len == 0) {
+            /* empty RPK */
+            SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_EMPTY_RAW_PUBLIC_KEY);
+            goto err;
+        }
+    } else {
+        spki_len = cert_len;
+    }
+
+    if (!PACKET_get_bytes(pkt, &spki, spki_len)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+    spkistart = spki;
+    if ((pkey = d2i_PUBKEY_ex(NULL, &spki, spki_len, sctx->libctx, sctx->propq)) == NULL
+            || spki != (spkistart + spki_len)) {
+        SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+    if (EVP_PKEY_missing_parameters(pkey)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR,
+                 SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
+        goto err;
+    }
+
+    /* Process the Extensions block */
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        if (PACKET_remaining(pkt) != (cert_len - 3 - spki_len)) {
+            SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_LENGTH);
+            goto err;
+        }
+        if (!PACKET_as_length_prefixed_2(pkt, &extensions)
+                || PACKET_remaining(pkt) != 0) {
+            SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+        if (!tls_collect_extensions(sc, &extensions, SSL_EXT_TLS1_3_RAW_PUBLIC_KEY,
+                                    &rawexts, NULL, 1)) {
+            /* SSLfatal already called */
+            goto err;
+        }
+        /* chain index is always zero and fin always 1 for RPK */
+        if (!tls_parse_all_extensions(sc, SSL_EXT_TLS1_3_RAW_PUBLIC_KEY,
+                                      rawexts, NULL, 0, 1)) {
+            /* SSLfatal already called */
+            goto err;
+        }
+    }
+    ret = 1;
+    if (peer_rpk != NULL) {
+        *peer_rpk = pkey;
+        pkey = NULL;
+    }
+
+ err:
+    OPENSSL_free(rawexts);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+unsigned long tls_output_rpk(SSL_CONNECTION *sc, WPACKET *pkt, CERT_PKEY *cpk)
+{
+    int pdata_len = 0;
+    unsigned char *pdata = NULL;
+    X509_PUBKEY *xpk = NULL;
+    unsigned long ret = 0;
+    X509 *x509 = NULL;
+
+    if (cpk != NULL && cpk->x509 != NULL) {
+        x509 = cpk->x509;
+        /* Get the RPK from the certificate */
+        xpk = X509_get_X509_PUBKEY(cpk->x509);
+        if (xpk == NULL) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        pdata_len = i2d_X509_PUBKEY(xpk, &pdata);
+    } else if (cpk != NULL && cpk->privatekey != NULL) {
+        /* Get the RPK from the private key */
+        pdata_len = i2d_PUBKEY(cpk->privatekey, &pdata);
+    } else {
+        /* The server RPK is not optional */
+        if (sc->server) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* The client can send a zero length certificate list */
+        if (!WPACKET_sub_memcpy_u24(pkt, pdata, pdata_len)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        return 1;
+    }
+
+    if (pdata_len <= 0) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * TLSv1.2 is _just_ the raw public key
+     * TLSv1.3 includes extensions, so there's a length wrapper
+     */
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        if (!WPACKET_start_sub_packet_u24(pkt)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (!WPACKET_sub_memcpy_u24(pkt, pdata, pdata_len)) {
+        SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        /*
+         * Only send extensions relevent to raw public keys. Until such
+         * extensions are defined, this will be an empty set of extensions.
+         * |x509| may be NULL, which raw public-key extensions need to handle.
+         */
+        if (!tls_construct_extensions(sc, pkt, SSL_EXT_TLS1_3_RAW_PUBLIC_KEY,
+                                      x509, 0)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+        if (!WPACKET_close(pkt)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    ret = 1;
+ err:
+    OPENSSL_free(pdata);
+    return ret;
+}
+
 unsigned long ssl3_output_cert_chain(SSL_CONNECTION *s, WPACKET *pkt,
                                      CERT_PKEY *cpk, int for_comp)
 {
index 30b7d5b0a560ccd0e0b4454a8c6514f9a304bc6c..04114b1e27d7f0821fb80566bae8b78fb864ac98 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -173,6 +173,13 @@ __owur CON_FUNC_RETURN tls_construct_cert_status(SSL_CONNECTION *s,
                                                  WPACKET *pkt);
 __owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL_CONNECTION *s,
                                                    PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_server_rpk(SSL_CONNECTION *sc,
+                                                 PACKET *pkt);
+__owur MSG_PROCESS_RETURN tls_process_client_rpk(SSL_CONNECTION *sc,
+                                                 PACKET *pkt);
+__owur unsigned long tls_output_rpk(SSL_CONNECTION *sc, WPACKET *pkt,
+                                    CERT_PKEY *cpk);
+__owur int tls_process_rpk(SSL_CONNECTION *s, PACKET *pkt, EVP_PKEY **peer_rpk);
 __owur MSG_PROCESS_RETURN tls_process_server_certificate(SSL_CONNECTION *s,
                                                          PACKET *pkt);
 __owur WORK_STATE tls_post_process_server_certificate(SSL_CONNECTION *s,
@@ -536,3 +543,30 @@ int tls_handle_alpn(SSL_CONNECTION *s);
 
 int tls13_save_handshake_digest_for_pha(SSL_CONNECTION *s);
 int tls13_restore_handshake_digest_for_pha(SSL_CONNECTION *s);
+
+__owur EVP_PKEY* tls_get_peer_pkey(const SSL_CONNECTION *sc);
+/* RFC7250 */
+EXT_RETURN tls_construct_ctos_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_stoc_client_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx);
+int tls_parse_ctos_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx);
+int tls_parse_stoc_client_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                               X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_ctos_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx);
+EXT_RETURN tls_construct_stoc_server_cert_type(SSL_CONNECTION *sc, WPACKET *pkt,
+                                               unsigned int context,
+                                               X509 *x, size_t chainidx);
+int tls_parse_ctos_server_cert_type(SSL_CONNECTION *sc, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx);
+int tls_parse_stoc_server_cert_type(SSL_CONNECTION *s, PACKET *pkt,
+                                    unsigned int context,
+                                    X509 *x, size_t chainidx);
index 3137f548efe3cdc200535aff3d6c36cbedeedf98..ddc74883f5bd37e86b02027ba1d992d582122f02 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.
  *
@@ -47,6 +47,11 @@ IMPLEMENT_ASN1_FUNCTIONS(GOST_KX_MESSAGE)
 static CON_FUNC_RETURN tls_construct_encrypted_extensions(SSL_CONNECTION *s,
                                                           WPACKET *pkt);
 
+static ossl_inline int received_client_cert(const SSL_CONNECTION *sc)
+{
+    return sc->session->peer_rpk != NULL || sc->session->peer != NULL;
+}
+
 /*
  * ossl_statem_server13_read_transition() encapsulates the logic for the allowed
  * handshake state transitions when a TLSv1.3 server is reading messages from
@@ -109,7 +114,7 @@ static int ossl_statem_server13_read_transition(SSL_CONNECTION *s, int mt)
 
     case TLS_ST_SR_COMP_CERT:
     case TLS_ST_SR_CERT:
-        if (s->session->peer == NULL) {
+        if (!received_client_cert(s)) {
             if (mt == SSL3_MT_FINISHED) {
                 st->hand_state = TLS_ST_SR_FINISHED;
                 return 1;
@@ -250,7 +255,7 @@ int ossl_statem_server_read_transition(SSL_CONNECTION *s, int mt)
          * the case of static DH). In that case |st->no_cert_verify| should be
          * set.
          */
-        if (s->session->peer == NULL || st->no_cert_verify) {
+        if (!received_client_cert(s) || st->no_cert_verify) {
             if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
                 /*
                  * For the ECDH ciphersuites when the client sends its ECDH
@@ -444,6 +449,13 @@ int send_certificate_request(SSL_CONNECTION *s)
     return 0;
 }
 
+static int do_compressed_cert(SSL_CONNECTION *sc)
+{
+    /* If we negotiated RPK, we won't attempt to compress it */
+    return sc->ext.server_cert_type == TLSEXT_cert_type_x509
+        && get_compressed_certificate_alg(sc) != TLSEXT_comp_cert_none;
+}
+
 /*
  * ossl_statem_server13_write_transition() works out what handshake state to
  * move to next when a TLSv1.3 server is writing messages to be sent to the
@@ -506,7 +518,7 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL_CONNECTION *s)
             st->hand_state = TLS_ST_SW_FINISHED;
         else if (send_certificate_request(s))
             st->hand_state = TLS_ST_SW_CERT_REQ;
-        else if (get_compressed_certificate_alg(s) != TLSEXT_comp_cert_none)
+        else if (do_compressed_cert(s))
             st->hand_state = TLS_ST_SW_COMP_CERT;
         else
             st->hand_state = TLS_ST_SW_CERT;
@@ -517,7 +529,7 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL_CONNECTION *s)
         if (s->post_handshake_auth == SSL_PHA_REQUEST_PENDING) {
             s->post_handshake_auth = SSL_PHA_REQUESTED;
             st->hand_state = TLS_ST_OK;
-        } else if (get_compressed_certificate_alg(s) != TLSEXT_comp_cert_none) {
+        } else if (do_compressed_cert(s)) {
             st->hand_state = TLS_ST_SW_COMP_CERT;
         } else {
             st->hand_state = TLS_ST_SW_CERT;
@@ -3243,7 +3255,7 @@ static int tls_process_cke_gost(SSL_CONNECTION *s, PACKET *pkt)
      * EVP_PKEY_derive_set_peer, because it is completely valid to use a
      * client certificate for authorization only.
      */
-    client_pub_pkey = X509_get0_pubkey(s->session->peer);
+    client_pub_pkey = tls_get_peer_pkey(s);
     if (client_pub_pkey) {
         if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
             ERR_clear_error();
@@ -3485,7 +3497,7 @@ WORK_STATE tls_post_process_client_key_exchange(SSL_CONNECTION *s,
     }
 #endif
 
-    if (s->statem.no_cert_verify || !s->session->peer) {
+    if (s->statem.no_cert_verify || !received_client_cert(s)) {
         /*
          * No certificate verify or no peer certificate so we no longer need
          * the handshake_buffer
@@ -3513,6 +3525,91 @@ WORK_STATE tls_post_process_client_key_exchange(SSL_CONNECTION *s,
     return WORK_FINISHED_CONTINUE;
 }
 
+MSG_PROCESS_RETURN tls_process_client_rpk(SSL_CONNECTION *sc, PACKET *pkt)
+{
+    MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR;
+    SSL_SESSION *new_sess = NULL;
+    EVP_PKEY *peer_rpk = NULL;
+
+    if (!tls_process_rpk(sc, pkt, &peer_rpk)) {
+        /* SSLfatal already called */
+        goto err;
+    }
+
+    if (peer_rpk == NULL) {
+        if ((sc->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+                && (sc->verify_mode & SSL_VERIFY_PEER)) {
+            SSLfatal(sc, SSL_AD_CERTIFICATE_REQUIRED,
+                     SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+            goto err;
+        }
+    } else {
+        if (ssl_verify_rpk(sc, peer_rpk) <= 0) {
+            SSLfatal(sc, ssl_x509err2alert(sc->verify_result),
+                     SSL_R_CERTIFICATE_VERIFY_FAILED);
+            goto err;
+        }
+    }
+
+    /*
+     * Sessions must be immutable once they go into the session cache. Otherwise
+     * we can get multi-thread problems. Therefore we don't "update" sessions,
+     * we replace them with a duplicate. Here, we need to do this every time
+     * a new RPK (or certificate) is received via post-handshake authentication,
+     * as the session may have already gone into the session cache.
+     */
+
+    if (sc->post_handshake_auth == SSL_PHA_REQUESTED) {
+        if ((new_sess = ssl_session_dup(sc->session, 0)) == NULL) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        SSL_SESSION_free(sc->session);
+        sc->session = new_sess;
+    }
+
+    /* Ensure there is no peer/peer_chain */
+    X509_free(sc->session->peer);
+    sc->session->peer = NULL;
+    sk_X509_pop_free(sc->session->peer_chain, X509_free);
+    sc->session->peer_chain = NULL;
+    /* Save RPK */
+    EVP_PKEY_free(sc->session->peer_rpk);
+    sc->session->peer_rpk = peer_rpk;
+    peer_rpk = NULL;
+
+    sc->session->verify_result = sc->verify_result;
+
+    /*
+     * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
+     * message
+     */
+    if (SSL_CONNECTION_IS_TLS13(sc)) {
+        if (!ssl3_digest_cached_records(sc, 1)) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+
+        /* Save the current hash state for when we receive the CertificateVerify */
+        if (!ssl_handshake_hash(sc, sc->cert_verify_hash,
+                                sizeof(sc->cert_verify_hash),
+                                &sc->cert_verify_hash_len)) {
+            /* SSLfatal() already called */;
+            goto err;
+        }
+
+        /* resend session tickets */
+        sc->sent_tickets = 0;
+    }
+
+    ret = MSG_PROCESS_CONTINUE_READING;
+
+ err:
+    EVP_PKEY_free(peer_rpk);
+    return ret;
+}
+
 MSG_PROCESS_RETURN tls_process_client_certificate(SSL_CONNECTION *s,
                                                   PACKET *pkt)
 {
@@ -3534,6 +3631,15 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL_CONNECTION *s,
     if (s->rlayer.rrlmethod->set_plain_alerts != NULL)
         s->rlayer.rrlmethod->set_plain_alerts(s->rlayer.rrl, 0);
 
+    if (s->ext.client_cert_type == TLSEXT_cert_type_rpk)
+        return tls_process_client_rpk(s, pkt);
+
+    if (s->ext.client_cert_type != TLSEXT_cert_type_x509) {
+        SSLfatal(s, SSL_AD_UNSUPPORTED_CERTIFICATE,
+                 SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        goto err;
+    }
+
     if ((sk = sk_X509_new_null()) == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
         goto err;
@@ -3665,6 +3771,9 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL_CONNECTION *s,
     OSSL_STACK_OF_X509_free(s->session->peer_chain);
     s->session->peer_chain = sk;
     sk = NULL;
+    /* Ensure there is no RPK */
+    EVP_PKEY_free(s->session->peer_rpk);
+    s->session->peer_rpk = NULL;
 
     /*
      * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
@@ -3733,9 +3842,22 @@ CON_FUNC_RETURN tls_construct_server_certificate(SSL_CONNECTION *s, WPACKET *pkt
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return CON_FUNC_ERROR;
     }
-    if (!ssl3_output_cert_chain(s, pkt, cpk, 0)) {
-        /* SSLfatal() already called */
-        return CON_FUNC_ERROR;
+    switch (s->ext.server_cert_type) {
+    case TLSEXT_cert_type_rpk:
+        if (!tls_output_rpk(s, pkt, cpk)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        break;
+    case TLSEXT_cert_type_x509:
+        if (!ssl3_output_cert_chain(s, pkt, cpk, 0)) {
+            /* SSLfatal() already called */
+            return 0;
+        }
+        break;
+    default:
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 
     return CON_FUNC_SUCCESS;
@@ -3869,7 +3991,8 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
      * create a fresh copy (not shared with other threads) to clean up
      */
     const_p = senc;
-    sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+    sess = d2i_SSL_SESSION_ex(NULL, &const_p, slen_full, sctx->libctx,
+                              sctx->propq);
     if (sess == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         goto err;
index e528467dd9ba29eea02ff7f576e6e16abf8ed9e9..189f241f7af4652ab89ed8cd40a7b06510b241db 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.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -2192,6 +2192,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
     SSL_HMAC *hctx = NULL;
     EVP_CIPHER_CTX *ctx = NULL;
     SSL_CTX *tctx = s->session_ctx;
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
 
     if (eticklen == 0) {
         /*
@@ -2263,7 +2264,6 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
             renew_ticket = 1;
     } else {
         EVP_CIPHER *aes256cbc = NULL;
-        SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
 
         /* Check key name matches */
         if (memcmp(etick, tctx->ext.tick_key_name,
@@ -2341,7 +2341,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
     slen += declen;
     p = sdec;
 
-    sess = d2i_SSL_SESSION(NULL, &p, slen);
+    sess = d2i_SSL_SESSION_ex(NULL, &p, slen, sctx->libctx, sctx->propq);
     slen -= p - sdec;
     OPENSSL_free(sdec);
     if (sess) {
@@ -3048,9 +3048,15 @@ int tls1_check_chain(SSL_CONNECTION *s, X509 *x, EVP_PKEY *pk,
     uint32_t *pvalid;
     unsigned int suiteb_flags = tls1_suiteb(s);
 
-    /* idx == -1 means checking server chains */
+    /*
+     * Meaning of idx:
+     * idx == -1 means SSL_check_chain() invocation
+     * idx == -2 means checking client certificate chains
+     * idx >= 0 means checking SSL_PKEY index
+     *
+     * For RPK, where there may be no cert, we ignore -1
+     */
     if (idx != -1) {
-        /* idx == -2 means checking client certificate chains */
         if (idx == -2) {
             cpk = c->key;
             idx = (int)(cpk - c->pkeys);
@@ -3061,13 +3067,19 @@ int tls1_check_chain(SSL_CONNECTION *s, X509 *x, EVP_PKEY *pk,
         pk = cpk->privatekey;
         chain = cpk->chain;
         strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT;
+        if (tls12_rpk_and_privkey(s, idx)) {
+            if (EVP_PKEY_is_a(pk, "EC") && !tls1_check_pkey_comp(s, pk))
+                return 0;
+            *pvalid = rv = CERT_PKEY_RPK;
+            return rv;
+        }
         /* If no cert or key, forget it */
-        if (!x || !pk)
+        if (x == NULL || pk == NULL)
             goto end;
     } else {
         size_t certidx;
 
-        if (!x || !pk)
+        if (x == NULL || pk == NULL)
             return 0;
 
         if (ssl_cert_lookup_by_pkey(pk, &certidx,
@@ -3487,6 +3499,10 @@ static int tls12_get_cert_sigalg_idx(const SSL_CONNECTION *s,
                 && (s->s3.tmp.new_cipher->algorithm_mkey & SSL_kRSA) != 0))
         return -1;
 
+    /* If doing RPK, the CERT_PKEY won't be "valid" */
+    if (tls12_rpk_and_privkey(s, sig_idx))
+        return  s->s3.tmp.valid_flags[sig_idx] & CERT_PKEY_RPK ? sig_idx : -1;
+
     return s->s3.tmp.valid_flags[sig_idx] & CERT_PKEY_VALID ? sig_idx : -1;
 }
 
index a9b132d93b3d3f1795748b4717304ca2ca48a3d7..8d66bf51dd4d38d62795ec169ef56f6430cb2d21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2012-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -477,6 +477,8 @@ static const ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_application_layer_protocol_negotiation,
      "application_layer_protocol_negotiation"},
     {TLSEXT_TYPE_signed_certificate_timestamp, "signed_certificate_timestamps"},
+    {TLSEXT_TYPE_client_cert_type, "client_cert_type"},
+    {TLSEXT_TYPE_server_cert_type, "server_cert_type"},
     {TLSEXT_TYPE_padding, "padding"},
     {TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
     {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
@@ -627,6 +629,18 @@ static const ssl_trace_tbl ssl_comp_cert_tbl[] = {
     {TLSEXT_comp_cert_zstd, "zstd"}
 };
 
+/*
+ * "pgp" and "1609dot2" are defined in RFC7250,
+ * although OpenSSL doesn't support them, it can
+ * at least report them in traces
+ */
+static const ssl_trace_tbl ssl_cert_type_tbl[] = {
+    {TLSEXT_cert_type_x509, "x509"},
+    {TLSEXT_cert_type_pgp, "pgp"},
+    {TLSEXT_cert_type_rpk, "rpk"},
+    {TLSEXT_cert_type_1609dot2, "1609dot2"}
+};
+
 static void ssl_print_hex(BIO *bio, int indent, const char *name,
                           const unsigned char *msg, size_t msglen)
 {
@@ -910,6 +924,20 @@ static int ssl_print_extension(BIO *bio, int indent, int server,
         BIO_printf(bio, "max_early_data=%u\n", (unsigned int)max_early_data);
         break;
 
+    case TLSEXT_TYPE_server_cert_type:
+    case TLSEXT_TYPE_client_cert_type:
+        if (server) {
+            if (extlen != 1)
+                return 0;
+            return ssl_trace_list(bio, indent + 2, ext, 1, 1, ssl_cert_type_tbl);
+        }
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1, ssl_cert_type_tbl);
+
     default:
         BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2);
     }
@@ -1275,6 +1303,36 @@ static int ssl_print_certificate(BIO *bio, int indent,
     return 1;
 }
 
+static int ssl_print_raw_public_key(BIO *bio, const SSL *ssl, int server,
+                                    int indent, const unsigned char **pmsg,
+                                    size_t *pmsglen)
+{
+    EVP_PKEY *pkey;
+    size_t clen;
+    const unsigned char *msg = *pmsg;
+    size_t msglen = *pmsglen;
+
+    if (msglen < 3)
+        return 0;
+    clen = (msg[0] << 16) | (msg[1] << 8) | msg[2];
+    if (msglen < clen + 3)
+        return 0;
+
+    msg += 3;
+
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "raw_public_key, length=%d\n", (int)clen);
+
+    pkey = d2i_PUBKEY_ex(NULL, &msg, clen, ssl->ctx->libctx, ssl->ctx->propq);
+    if (pkey == NULL)
+        return 0;
+    EVP_PKEY_print_public(bio, pkey, indent + 2, NULL);
+    EVP_PKEY_free(pkey);
+    *pmsg += clen + 3;
+    *pmsglen -= clen + 3;
+    return 1;
+}
+
 static int ssl_print_certificates(BIO *bio, const SSL_CONNECTION *sc, int server,
                                   int indent, const unsigned char *msg,
                                   size_t msglen)
@@ -1291,6 +1349,16 @@ static int ssl_print_certificates(BIO *bio, const SSL_CONNECTION *sc, int server
     if (msglen != clen + 3)
         return 0;
     msg += 3;
+    if ((server && sc->ext.server_cert_type == TLSEXT_cert_type_rpk)
+            || (!server && sc->ext.client_cert_type == TLSEXT_cert_type_rpk)) {
+        if (!ssl_print_raw_public_key(bio, &sc->ssl, server, indent, &msg, &clen))
+            return 0;
+        if (SSL_CONNECTION_IS_TLS13(sc)
+            && !ssl_print_extensions(bio, indent + 2, server,
+                                     SSL3_MT_CERTIFICATE, &msg, &clen))
+            return 0;
+        return 1;
+    }
     BIO_indent(bio, indent, 80);
     BIO_printf(bio, "certificate_list, length=%d\n", (int)clen);
     while (clen > 0) {
index 56d53445dc9528e762dc3b353bc4ca905abd7aa7..4599770106cabecd7032a27d899e06896f52a04b 100644 (file)
@@ -66,6 +66,10 @@ IF[{- !$disabled{tests} -}]
           bio_tfo_test membio_test bio_dgram_test list_test fips_version_test \
           x509_test hpke_test pairwise_fail_test nodefltctxtest
 
+  IF[{- !$disabled{'rpk'} -}]
+    PROGRAMS{noinst}=rpktest
+  ENDIF
+
   IF[{- !$disabled{'deprecated-3.0'} -}]
     PROGRAMS{noinst}=enginetest
   ENDIF
@@ -485,6 +489,10 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[sslapitest]=../include ../apps/include ..
   DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a
 
+  SOURCE[rpktest]=rpktest.c helpers/ssltestlib.c
+  INCLUDE[rpktest]=../include ../apps/include ..
+  DEPEND[rpktest]=../libcrypto ../libssl libtestutil.a
+
   SOURCE[defltfips_test]=defltfips_test.c
   INCLUDE[defltfips_test]=../include  ../apps/include
   DEPEND[defltfips_test]=../libcrypto libtestutil.a
index 97a538abf9d4b890e187ff2d7e2da90a37e0361f..b86f82ebf98bc7cc6d4072c55393fca893319989 100644 (file)
@@ -61,6 +61,8 @@ static EXT_LIST ext_list[] = {
     EXT_ENTRY(extended_master_secret),
     EXT_ENTRY(signature_algorithms_cert),
     EXT_ENTRY(post_handshake_auth),
+    EXT_ENTRY(client_cert_type),
+    EXT_ENTRY(server_cert_type),
     EXT_ENTRY(signature_algorithms),
     EXT_ENTRY(supported_versions),
     EXT_ENTRY(psk_kex_modes),
diff --git a/test/recipes/70-test_certtypeext.t b/test/recipes/70-test_certtypeext.t
new file mode 100644 (file)
index 0000000..963468a
--- /dev/null
@@ -0,0 +1,96 @@
+#! /usr/bin/env perl
+# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+
+my $test_name = "test_certtypeext";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+    if $^O =~ /^(VMS)$/;
+
+plan skip_all => "$test_name needs the dynamic engine feature enabled"
+    if disabled("engine") || disabled("dynamic-engine");
+
+plan skip_all => "$test_name needs the sock feature enabled"
+    if disabled("sock");
+
+plan skip_all => "$test_name needs TLSv1.2 enabled"
+    if disabled("tls1_2");
+
+my $proxy = TLSProxy::Proxy->new(
+    \&certtype_filter,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+use constant {
+    SERVER_CERT_TYPE => 0,
+    CLIENT_CERT_TYPE => 1,
+    NO_CERT_TYPE => 2
+};
+my $testtype;
+
+# Test 1: Just do a verify without cert type
+$proxy->clear();
+$proxy->clientflags("-tls1_2 -cert ".srctop_file("apps", "server.pem"));
+$proxy->serverflags("-verify 4");
+$testtype = NO_CERT_TYPE;
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 4;
+ok(TLSProxy::Message->success, "Simple verify");
+
+# Test 2: Set a bogus server cert type
+$proxy->clear();
+$proxy->serverflags("-enable_server_rpk");
+$testtype = SERVER_CERT_TYPE;
+$proxy->start();
+ok(TLSProxy::Message->fail, "Unsupported server cert type");
+
+# Test 3: Set a bogus client cert type
+$proxy->clear();
+$proxy->serverflags("-enable_client_rpk");
+$testtype = CLIENT_CERT_TYPE;
+$proxy->start();
+ok(TLSProxy::Message->success, "Unsupported client cert type, no verify");
+
+# Test 4: Set a bogus server cert type with verify
+$proxy->clear();
+$testtype = CLIENT_CERT_TYPE;
+$proxy->clientflags("-tls1_2 -cert ".srctop_file("apps", "server.pem"));
+$proxy->serverflags("-verify 4 -enable_client_rpk");
+$proxy->start();
+ok(TLSProxy::Message->fail, "Unsupported client cert type with verify");
+
+sub certtype_filter
+{
+    my $proxy = shift;
+    my $message;
+
+    # We're only interested in the initial ClientHello
+    return if $proxy->flight != 0;
+
+    $message = ${$proxy->message_list}[0];
+
+    # Add unsupported and bogus client and server cert type to the client hello.
+    my $ct = pack "C5", 0x04, 0x01, 0x03, 0x55, 0x66;
+    if ($testtype == CLIENT_CERT_TYPE) {
+        print "SETTING CLIENT CERT TYPE\n";
+        $message->set_extension(TLSProxy::Message::EXT_CLIENT_CERT_TYPE, $ct);
+    }
+    if ($testtype == SERVER_CERT_TYPE) {
+        print "SETTING SERVER CERT TYPE\n";
+        $message->set_extension(TLSProxy::Message::EXT_SERVER_CERT_TYPE, $ct);
+    }
+
+    $message->repack();
+}
diff --git a/test/recipes/90-test_rpk.t b/test/recipes/90-test_rpk.t
new file mode 100644 (file)
index 0000000..2036817
--- /dev/null
@@ -0,0 +1,23 @@
+#! /usr/bin/env perl
+# Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use OpenSSL::Test::Utils;
+use OpenSSL::Test qw/:DEFAULT srctop_dir bldtop_dir/;
+
+BEGIN {
+    setup("test_rpk");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+
+plan skip_all => "RPK is disabled in this OpenSSL build" if disabled("tls1_2") && disabled("tls1_3");
+
+plan tests => 1;
+
+ok(run(test(["rpktest", srctop_dir("test", "certs")])), "running rpktest");
diff --git a/test/rpktest.c b/test/rpktest.c
new file mode 100644 (file)
index 0000000..89e1fcf
--- /dev/null
@@ -0,0 +1,759 @@
+/*
+ * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+#include <openssl/ssl.h>
+
+#include "helpers/ssltestlib.h"
+#include "internal/dane.h"
+#include "testutil.h"
+
+#undef OSSL_NO_USABLE_TLS1_3
+#if defined(OPENSSL_NO_TLS1_3) \
+    || (defined(OPENSSL_NO_EC) && defined(OPENSSL_NO_DH))
+/*
+ * If we don't have ec or dh then there are no built-in groups that are usable
+ * with TLSv1.3
+ */
+# define OSSL_NO_USABLE_TLS1_3
+#endif
+
+static char *certsdir = NULL;
+static char *rootcert = NULL;
+static char *cert = NULL;
+static char *privkey = NULL;
+static char *cert2 = NULL;
+static char *privkey2 = NULL;
+static char *cert448 = NULL;
+static char *privkey448 = NULL;
+static char *cert25519 = NULL;
+static char *privkey25519 = NULL;
+static OSSL_LIB_CTX *libctx = NULL;
+static OSSL_PROVIDER *defctxnull = NULL;
+
+static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
+static const unsigned char SID_CTX[] = { 'r', 'p', 'k' };
+
+static int rpk_verify_client_cb(int ok, X509_STORE_CTX *ctx)
+{
+    int err = X509_STORE_CTX_get_error(ctx);
+
+    if (X509_STORE_CTX_get0_rpk(ctx) != NULL) {
+        if (err != X509_V_OK) {
+            TEST_info("rpk_verify_client_cb: ok=%d err=%d", ok, err);
+            return 0;
+        }
+    }
+    return 1;
+}
+static int rpk_verify_server_cb(int ok, X509_STORE_CTX *ctx)
+{
+    int err = X509_STORE_CTX_get_error(ctx);
+
+    if (X509_STORE_CTX_get0_rpk(ctx) != NULL) {
+        if (err != X509_V_OK) {
+            TEST_info("rpk_verify_server_cb: ok=%d err=%d", ok, err);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/*
+ * Test dimensions:
+ *   (2) server_cert_type RPK off/on for server
+ *   (2) client_cert_type RPK off/on for server
+ *   (2) server_cert_type RPK off/on for client
+ *   (2) client_cert_type RPK off/on for client
+ *   (4) RSA vs ECDSA vs Ed25519 vs Ed448 certificates
+ *   (2) TLSv1.2 vs TLSv1.3
+ *
+ * Tests:
+ * idx = 0 - is the normal success case, certificate, single peer key
+ * idx = 1 - only a private key
+ * idx = 2 - add client authentication
+ * idx = 3 - add second peer key (rootcert.pem)
+ * idx = 4 - add second peer key (different, RSA or ECDSA)
+ * idx = 5 - reverse peer keys (rootcert.pem, different order)
+ * idx = 6 - reverse peer keys (RSA or ECDSA, different order)
+ * idx = 7 - expects failure due to mismatched key (RSA or ECDSA)
+ * idx = 8 - expects failure due to no configured key on client
+ * idx = 9 - add client authentication (PHA)
+ * idx = 10 - add client authentication (privake key only)
+ * idx = 11 - simple resumption
+ * idx = 12 - simple resumption, no ticket
+ * idx = 13 - resumption with client authentication
+ * idx = 14 - resumption with client authentication, no ticket
+ * idx = 15 - like 0, but use non-default libctx
+ *
+ * 16 * 2 * 4 * 2 * 2 * 2 * 2 = 2048 tests
+ */
+static int test_rpk(int idx)
+{
+# define RPK_TESTS 16
+# define RPK_DIMS (2 * 4 * 2 * 2 * 2 * 2)
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    EVP_PKEY *pkey = NULL, *other_pkey = NULL, *root_pkey = NULL;
+    X509 *x509 = NULL, *other_x509 = NULL, *root_x509 = NULL;
+    int testresult = 0, ret, expected = 1;
+    int client_expected = X509_V_OK;
+    int verify;
+    int tls_version;
+    char *cert_file = NULL;
+    char *privkey_file = NULL;
+    char *other_cert_file = NULL;
+    SSL_SESSION *client_sess = NULL;
+    SSL_SESSION *server_sess = NULL;
+    int idx_server_server_rpk, idx_server_client_rpk;
+    int idx_client_server_rpk, idx_client_client_rpk;
+    int idx_cert, idx_prot;
+    int client_auth = 0;
+    int resumption = 0;
+    long server_verify_result = 0;
+    long client_verify_result = 0;
+    OSSL_LIB_CTX *test_libctx = NULL;
+
+    if (!TEST_int_le(idx, RPK_TESTS * RPK_DIMS))
+        return 0;
+
+    idx_server_server_rpk = idx / (RPK_TESTS * 2 * 4 * 2 * 2 * 2);
+    idx %= RPK_TESTS * 2 * 4 * 2 * 2 * 2;
+    idx_server_client_rpk = idx / (RPK_TESTS * 2 * 4 * 2 * 2);
+    idx %= RPK_TESTS * 2 * 4 * 2 * 2;
+    idx_client_server_rpk = idx / (RPK_TESTS * 2 * 4 * 2);
+    idx %= RPK_TESTS * 2 * 4 * 2;
+    idx_client_client_rpk = idx / (RPK_TESTS * 2 * 4);
+    idx %= RPK_TESTS * 2 * 4;
+    idx_cert = idx / (RPK_TESTS * 2);
+    idx %= RPK_TESTS * 2;
+    idx_prot = idx / RPK_TESTS;
+    idx %= RPK_TESTS;
+
+    /* Load "root" cert/pubkey */
+    root_x509 = load_cert_pem(rootcert, NULL);
+    if (!TEST_ptr(root_x509))
+        goto end;
+    root_pkey = X509_get0_pubkey(root_x509);
+    if (!TEST_ptr(root_pkey))
+        goto end;
+
+    switch (idx_cert) {
+        case 0:
+            /* use RSA */
+            cert_file = cert;
+            privkey_file = privkey;
+            other_cert_file = cert2;
+            break;
+#ifndef OPENSSL_NO_ECDSA
+        case 1:
+            /* use ECDSA */
+            cert_file = cert2;
+            privkey_file = privkey2;
+            other_cert_file = cert;
+            break;
+        case 2:
+            /* use Ed448 */
+            cert_file = cert448;
+            privkey_file = privkey448;
+            other_cert_file = cert;
+            break;
+        case 3:
+            /* use Ed25519 */
+            cert_file = cert25519;
+            privkey_file = privkey25519;
+            other_cert_file = cert;
+            break;
+#endif
+        default:
+            testresult = TEST_skip("EDCSA disabled");
+            goto end;
+    }
+    /* Load primary cert */
+    x509 = load_cert_pem(cert_file, NULL);
+    if (!TEST_ptr(x509))
+        goto end;
+    pkey = X509_get0_pubkey(x509);
+    /* load other cert */
+    other_x509 = load_cert_pem(other_cert_file, NULL);
+    if (!TEST_ptr(other_x509))
+        goto end;
+    other_pkey = X509_get0_pubkey(other_x509);
+#ifdef OPENSSL_NO_ECDSA
+    /* Can't get other_key if it's ECDSA */
+    if (other_pkey == NULL && idx_cert == 0
+            && (idx == 4 || idx == 6 || idx == 7)) {
+        testresult = TEST_skip("EDCSA disabled");
+        goto end;
+    }
+#endif
+
+    switch (idx_prot) {
+    case 0:
+#ifdef OSSL_NO_USABLE_TLS1_3
+        testresult = TEST_skip("TLSv1.3 disabled");
+        goto end;
+#else
+        tls_version = TLS1_3_VERSION;
+        break;
+#endif
+    case 1:
+#ifdef OPENSSL_NO_TLS1_2
+        testresult = TEST_skip("TLSv1.2 disabled");
+        goto end;
+#else
+        tls_version = TLS1_2_VERSION;
+        break;
+#endif
+    default:
+        goto end;
+    }
+
+    if (idx == 15) {
+        test_libctx = libctx;
+        defctxnull = OSSL_PROVIDER_load(NULL, "null");
+        if (!TEST_ptr(defctxnull))
+            goto end;
+    }
+    if (!TEST_true(create_ssl_ctx_pair(test_libctx,
+                                       TLS_server_method(), TLS_client_method(),
+                                       tls_version, tls_version,
+                                       &sctx, &cctx, NULL, NULL)))
+        goto end;
+
+    if (idx_server_server_rpk)
+        if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_rpk, sizeof(cert_type_rpk))))
+            goto end;
+    if (idx_server_client_rpk)
+        if (!TEST_true(SSL_CTX_set1_client_cert_type(sctx, cert_type_rpk, sizeof(cert_type_rpk))))
+            goto end;
+    if (idx_client_server_rpk)
+        if (!TEST_true(SSL_CTX_set1_server_cert_type(cctx, cert_type_rpk, sizeof(cert_type_rpk))))
+            goto end;
+    if (idx_client_client_rpk)
+        if (!TEST_true(SSL_CTX_set1_client_cert_type(cctx, cert_type_rpk, sizeof(cert_type_rpk))))
+            goto end;
+    if (!TEST_true(SSL_CTX_set_session_id_context(sctx, SID_CTX, sizeof(SID_CTX))))
+        goto end;
+    if (!TEST_true(SSL_CTX_set_session_id_context(cctx, SID_CTX, sizeof(SID_CTX))))
+        goto end;
+
+    if (!TEST_int_gt(SSL_CTX_dane_enable(sctx), 0))
+        goto end;
+    if (!TEST_int_gt(SSL_CTX_dane_enable(cctx), 0))
+        goto end;
+
+    /* NEW */
+    SSL_CTX_set_verify(cctx, SSL_VERIFY_PEER, rpk_verify_client_cb);
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                      NULL, NULL)))
+        goto end;
+
+    if (!TEST_int_gt(SSL_dane_enable(serverssl, NULL), 0))
+        goto end;
+    if (!TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0))
+        goto end;
+
+    /* Set private key and certificate */
+    if (!TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1))
+        goto end;
+    /* Only a private key */
+    if (idx == 1) {
+        if (idx_server_server_rpk == 0 || idx_client_server_rpk == 0)
+            expected = 0;
+    } else {
+        /* Add certificate */
+        if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(serverssl), 1))
+            goto end;
+    }
+
+    switch (idx) {
+    default:
+        if (!TEST_true(idx < RPK_TESTS))
+            goto end;
+        break;
+    case 0:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        break;
+    case 1:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        break;
+    case 2:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey)))
+            goto end;
+        /* Use the same key for client auth */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+            goto end;
+        SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+        client_auth = 1;
+        break;
+    case 3:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, root_pkey)))
+            goto end;
+        break;
+    case 4:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey)))
+            goto end;
+        break;
+    case 5:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, root_pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        break;
+    case 6:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        break;
+    case 7:
+        if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1)
+            client_expected = -1;
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, other_pkey)))
+            goto end;
+        client_verify_result = X509_V_ERR_DANE_NO_MATCH;
+        break;
+    case 8:
+        if (idx_server_server_rpk == 1 && idx_client_server_rpk == 1)
+            client_expected = -1;
+        /* no peer keys */
+        client_verify_result = X509_V_ERR_RPK_UNTRUSTED;
+        break;
+    case 9:
+        if (tls_version != TLS1_3_VERSION) {
+            testresult = TEST_skip("PHA requires TLSv1.3");
+            goto end;
+        }
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey)))
+            goto end;
+        /* Use the same key for client auth */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+            goto end;
+        SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_POST_HANDSHAKE, rpk_verify_server_cb);
+        SSL_set_post_handshake_auth(clientssl, 1);
+        client_auth = 1;
+        break;
+    case 10:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey)))
+            goto end;
+        /* Use the same key for client auth */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        /* Since there's no cert, this is expected to fail without RPK support */
+        if (!idx_server_client_rpk || !idx_client_client_rpk)
+            expected = 0;
+        SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+        client_auth = 1;
+        break;
+    case 11:
+        if (!idx_server_server_rpk || !idx_client_server_rpk) {
+            testresult = TEST_skip("Only testing resumption with server RPK");
+            goto end;
+        }
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        resumption = 1;
+        break;
+    case 12:
+        if (!idx_server_server_rpk || !idx_client_server_rpk) {
+            testresult = TEST_skip("Only testing resumption with server RPK");
+            goto end;
+        }
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        SSL_set_options(serverssl, SSL_OP_NO_TICKET);
+        SSL_set_options(clientssl, SSL_OP_NO_TICKET);
+        resumption = 1;
+        break;
+    case 13:
+        if (!idx_server_server_rpk || !idx_client_server_rpk) {
+            testresult = TEST_skip("Only testing resumption with server RPK");
+            goto end;
+        }
+        if (!idx_server_client_rpk || !idx_client_client_rpk) {
+            testresult = TEST_skip("Only testing client authentication resumption with client RPK");
+            goto end;
+        }
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey)))
+            goto end;
+        /* Use the same key for client auth */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+            goto end;
+        SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+        client_auth = 1;
+        resumption = 1;
+        break;
+    case 14:
+        if (!idx_server_server_rpk || !idx_client_server_rpk) {
+            testresult = TEST_skip("Only testing resumption with server RPK");
+            goto end;
+        }
+        if (!idx_server_client_rpk || !idx_client_client_rpk) {
+            testresult = TEST_skip("Only testing client authentication resumption with client RPK");
+            goto end;
+        }
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        if (!TEST_true(SSL_add_expected_rpk(serverssl, pkey)))
+            goto end;
+        /* Use the same key for client auth */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+            goto end;
+        SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+        SSL_set_options(serverssl, SSL_OP_NO_TICKET);
+        SSL_set_options(clientssl, SSL_OP_NO_TICKET);
+        client_auth = 1;
+        resumption = 1;
+        break;
+    case 15:
+        if (!TEST_true(SSL_add_expected_rpk(clientssl, pkey)))
+            goto end;
+        break;
+    }
+
+    ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE);
+    if (!TEST_int_eq(expected, ret))
+        goto end;
+
+    /* Make sure client gets RPK or certificate as configured */
+    if (expected == 1) {
+        if (idx_server_server_rpk && idx_client_server_rpk) {
+            if (!TEST_long_eq(SSL_get_verify_result(clientssl), client_verify_result))
+                goto end;
+            if (!TEST_ptr(SSL_get0_peer_rpk(clientssl)))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_rpk))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_rpk))
+                goto end;
+        } else {
+            if (!TEST_ptr(SSL_get0_peer_certificate(clientssl)))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_x509))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_x509))
+                goto end;
+        }
+    }
+
+    if (idx == 9) {
+        /* Make PHA happen... */
+        if (!TEST_true(SSL_verify_client_post_handshake(serverssl)))
+            goto end;
+        if (!TEST_true(SSL_do_handshake(serverssl)))
+            goto end;
+        if (!TEST_int_le(SSL_read(clientssl, NULL, 0), 0))
+            goto end;
+        if (!TEST_int_le(SSL_read(serverssl, NULL, 0), 0))
+            goto end;
+    }
+
+    /* Make sure server gets an RPK or certificate as configured */
+    if (client_auth) {
+        if (idx_server_client_rpk && idx_client_client_rpk) {
+            if (!TEST_long_eq(SSL_get_verify_result(serverssl), server_verify_result))
+                goto end;
+            if (!TEST_ptr(SSL_get0_peer_rpk(serverssl)))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_rpk))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_rpk))
+                goto end;
+        } else {
+            /* only if connection is expected to succeed */
+            if (expected == 1 && !TEST_ptr(SSL_get0_peer_certificate(serverssl)))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_x509))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_x509))
+                goto end;
+        }
+    }
+
+    if (resumption) {
+        EVP_PKEY *client_pkey = NULL;
+        EVP_PKEY *server_pkey = NULL;
+
+        if (!TEST_ptr((client_sess = SSL_get1_session(clientssl)))
+                || !TEST_ptr((client_pkey = SSL_SESSION_get0_peer_rpk(client_sess))))
+            goto end;
+        if (client_auth) {
+            if (!TEST_ptr((server_sess = SSL_get1_session(serverssl)))
+                || !TEST_ptr((server_pkey = SSL_SESSION_get0_peer_rpk(server_sess))))
+            goto end;
+        }
+        SSL_shutdown(clientssl);
+        SSL_shutdown(serverssl);
+        SSL_free(clientssl);
+        SSL_free(serverssl);
+        serverssl = clientssl = NULL;
+
+        if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                          NULL, NULL))
+                || !TEST_true(SSL_set_session(clientssl, client_sess)))
+            goto end;
+
+        /* Set private key (and maybe certificate) */
+        if (!TEST_int_eq(SSL_use_PrivateKey_file(serverssl, privkey_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_use_certificate_file(serverssl, cert_file, SSL_FILETYPE_PEM), 1))
+            goto end;
+        if (!TEST_int_eq(SSL_check_private_key(serverssl), 1))
+            goto end;
+        if (!TEST_int_gt(SSL_dane_enable(serverssl, "example.com"), 0))
+            goto end;
+        if (!TEST_int_gt(SSL_dane_enable(clientssl, "example.com"), 0))
+            goto end;
+
+        switch (idx) {
+        default:
+            break;
+        case 11:
+            if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey)))
+                goto end;
+            break;
+        case 12:
+            if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey)))
+                goto end;
+            SSL_set_options(clientssl, SSL_OP_NO_TICKET);
+            SSL_set_options(serverssl, SSL_OP_NO_TICKET);
+            break;
+        case 13:
+            if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey)))
+                goto end;
+            if (!TEST_true(SSL_add_expected_rpk(serverssl, server_pkey)))
+                goto end;
+            /* Use the same key for client auth */
+            if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+                goto end;
+            if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+                goto end;
+            if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+                goto end;
+            SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+            break;
+        case 14:
+            if (!TEST_true(SSL_add_expected_rpk(clientssl, client_pkey)))
+                goto end;
+            if (!TEST_true(SSL_add_expected_rpk(serverssl, server_pkey)))
+                goto end;
+            /* Use the same key for client auth */
+            if (!TEST_int_eq(SSL_use_PrivateKey_file(clientssl, privkey_file, SSL_FILETYPE_PEM), 1))
+                goto end;
+            if (!TEST_int_eq(SSL_use_certificate_file(clientssl, cert_file, SSL_FILETYPE_PEM), 1))
+                goto end;
+            if (!TEST_int_eq(SSL_check_private_key(clientssl), 1))
+                goto end;
+            SSL_set_verify(serverssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, rpk_verify_server_cb);
+            SSL_set_options(serverssl, SSL_OP_NO_TICKET);
+            SSL_set_options(clientssl, SSL_OP_NO_TICKET);
+            break;
+        }
+
+        ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE);
+        if (!TEST_int_eq(expected, ret))
+            goto end;
+        verify = SSL_get_verify_result(clientssl);
+        if (!TEST_int_eq(client_expected, verify))
+            goto end;
+        if (!TEST_true(SSL_session_reused(clientssl)))
+            goto end;
+
+        if (!TEST_ptr(SSL_get0_peer_rpk(clientssl)))
+            goto end;
+        if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(serverssl), TLSEXT_cert_type_rpk))
+            goto end;
+        if (!TEST_int_eq(SSL_get_negotiated_server_cert_type(clientssl), TLSEXT_cert_type_rpk))
+            goto end;
+
+        if (client_auth) {
+            if (!TEST_ptr(SSL_get0_peer_rpk(serverssl)))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(serverssl), TLSEXT_cert_type_rpk))
+                goto end;
+            if (!TEST_int_eq(SSL_get_negotiated_client_cert_type(clientssl), TLSEXT_cert_type_rpk))
+                goto end;
+        }
+    }
+
+    testresult = 1;
+
+ end:
+    OSSL_PROVIDER_unload(defctxnull);
+    defctxnull = NULL;
+    SSL_SESSION_free(client_sess);
+    SSL_SESSION_free(server_sess);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    X509_free(x509);
+    X509_free(other_x509);
+    X509_free(root_x509);
+
+    if (testresult == 0) {
+        TEST_info("idx_ss_rpk=%d, idx_sc_rpk=%d, idx_cs_rpk=%d, idx_cc_rpk=%d, idx_cert=%d, idx_prot=%d, idx=%d",
+                  idx_server_server_rpk, idx_server_client_rpk,
+                  idx_client_server_rpk, idx_client_client_rpk,
+                  idx_cert, idx_prot, idx);
+    }
+    return testresult;
+}
+
+static int test_rpk_api(void)
+{
+    int ret = 0;
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    unsigned char cert_type_dups[] = { TLSEXT_cert_type_rpk,
+                                       TLSEXT_cert_type_x509,
+                                       TLSEXT_cert_type_x509 };
+    unsigned char cert_type_bad[] = { 0xFF };
+    unsigned char cert_type_extra[] = { TLSEXT_cert_type_rpk,
+                                        TLSEXT_cert_type_x509,
+                                        0xFF };
+    unsigned char cert_type_unsup[] = { TLSEXT_cert_type_pgp,
+                                        TLSEXT_cert_type_1609dot2 };
+    unsigned char cert_type_just_x509[] = { TLSEXT_cert_type_x509 };
+    unsigned char cert_type_just_rpk[] = { TLSEXT_cert_type_rpk };
+
+    if (!TEST_true(create_ssl_ctx_pair(NULL,
+                                       TLS_server_method(), TLS_client_method(),
+                                       TLS1_2_VERSION, TLS1_2_VERSION,
+                                       &sctx, &cctx, NULL, NULL)))
+        goto end;
+
+    if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_dups, sizeof(cert_type_dups))))
+        goto end;
+
+    if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_bad, sizeof(cert_type_bad))))
+        goto end;
+
+    if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_extra, sizeof(cert_type_extra))))
+        goto end;
+
+    if (!TEST_false(SSL_CTX_set1_server_cert_type(sctx, cert_type_unsup, sizeof(cert_type_unsup))))
+        goto end;
+
+    if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_just_x509, sizeof(cert_type_just_x509))))
+        goto end;
+
+    if (!TEST_true(SSL_CTX_set1_server_cert_type(sctx, cert_type_just_rpk, sizeof(cert_type_just_rpk))))
+        goto end;
+
+    ret = 1;
+ end:
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    return ret;
+}
+OPT_TEST_DECLARE_USAGE("certdir\n")
+
+int setup_tests(void)
+{
+    if (!test_skip_common_options()) {
+        TEST_error("Error parsing test options\n");
+        return 0;
+    }
+
+    if (!TEST_ptr(certsdir = test_get_argument(0)))
+        return 0;
+
+    rootcert = test_mk_file_path(certsdir, "rootcert.pem");
+    if (rootcert == NULL)
+        goto err;
+
+    cert = test_mk_file_path(certsdir, "servercert.pem");
+    if (cert == NULL)
+        goto err;
+
+    privkey = test_mk_file_path(certsdir, "serverkey.pem");
+    if (privkey == NULL)
+        goto err;
+
+    cert2 = test_mk_file_path(certsdir, "server-ecdsa-cert.pem");
+    if (cert2 == NULL)
+        goto err;
+
+    privkey2 = test_mk_file_path(certsdir, "server-ecdsa-key.pem");
+    if (privkey2 == NULL)
+        goto err;
+
+    cert448 = test_mk_file_path(certsdir, "server-ed448-cert.pem");
+    if (cert2 == NULL)
+        goto err;
+
+    privkey448 = test_mk_file_path(certsdir, "server-ed448-key.pem");
+    if (privkey2 == NULL)
+        goto err;
+
+    cert25519 = test_mk_file_path(certsdir, "server-ed25519-cert.pem");
+    if (cert2 == NULL)
+        goto err;
+
+    privkey25519 = test_mk_file_path(certsdir, "server-ed25519-key.pem");
+    if (privkey2 == NULL)
+        goto err;
+
+    libctx = OSSL_LIB_CTX_new();
+    if (libctx == NULL)
+        goto err;
+
+    ADD_TEST(test_rpk_api);
+    ADD_ALL_TESTS(test_rpk, RPK_TESTS * RPK_DIMS);
+    return 1;
+
+ err:
+    return 0;
+}
+
+void cleanup_tests(void)
+{
+    OPENSSL_free(rootcert);
+    OPENSSL_free(cert);
+    OPENSSL_free(privkey);
+    OPENSSL_free(cert2);
+    OPENSSL_free(privkey2);
+    OPENSSL_free(cert448);
+    OPENSSL_free(privkey448);
+    OPENSSL_free(cert25519);
+    OPENSSL_free(privkey25519);
+    OSSL_LIB_CTX_free(libctx);
+ }
index 9cf4cf7d35636439c838099115c4f8739adf831c..ae4977bfde1442fa149528eeb37e36eda957c365 100644 (file)
@@ -8090,7 +8090,7 @@ static int test_ticket_callbacks(int tst)
     gen_tick_called = dec_tick_called = tick_key_cb_called = 0;
 
     /* Which tests the ticket key callback should request renewal for */
-    
+
     if (tst == 10 || tst == 11 || tst == 16 || tst == 17)
         tick_key_renew = 1;
     else if (tst == 12 || tst == 13 || tst == 18 || tst == 19)
@@ -9558,9 +9558,12 @@ static int create_cert_key(int idx, char *certfilename, char *privkeyfilename)
  * correctly establish a TLS (1.3) connection.
  * Test 0: Signature algorithm with built-in hashing functionality: "xorhmacsig"
  * Test 1: Signature algorithm using external SHA2 hashing: "xorhmacsha2sig"
+ * Test 2: Test 0 using RPK
+ * Test 3: Test 1 using RPK
  */
 static int test_pluggable_signature(int idx)
 {
+    static const unsigned char cert_type_rpk[] = { TLSEXT_cert_type_rpk, TLSEXT_cert_type_x509 };
     SSL_CTX *cctx = NULL, *sctx = NULL;
     SSL *clientssl = NULL, *serverssl = NULL;
     int testresult = 0;
@@ -9568,10 +9571,12 @@ static int test_pluggable_signature(int idx)
     OSSL_PROVIDER *defaultprov = OSSL_PROVIDER_load(libctx, "default");
     char *certfilename = "tls-prov-cert.pem";
     char *privkeyfilename = "tls-prov-key.pem";
+    int sigidx = idx % 2;
+    int rpkidx = idx / 2;
 
     /* create key and certificate for the different algorithm types */
     if (!TEST_ptr(tlsprov)
-        || !TEST_true(create_cert_key(idx, certfilename, privkeyfilename)))
+        || !TEST_true(create_cert_key(sigidx, certfilename, privkeyfilename)))
         goto end;
 
     if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
@@ -9583,6 +9588,13 @@ static int test_pluggable_signature(int idx)
                                              NULL, NULL)))
         goto end;
 
+    /* Enable RPK for server cert */
+    if (rpkidx) {
+        if (!TEST_true(SSL_set1_server_cert_type(serverssl, cert_type_rpk, sizeof(cert_type_rpk)))
+                || !TEST_true(SSL_set1_server_cert_type(clientssl, cert_type_rpk, sizeof(cert_type_rpk))))
+            goto end;
+    }
+
     /* This is necessary to pass minimal setup w/o other groups configured */
     if (!TEST_true(SSL_set1_groups_list(serverssl, "xorgroup"))
             || !TEST_true(SSL_set1_groups_list(clientssl, "xorgroup")))
@@ -9596,6 +9608,10 @@ static int test_pluggable_signature(int idx)
     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
         goto end;
 
+    /* If using RPK, make sure we got one */
+    if (rpkidx && !TEST_long_eq(SSL_get_verify_result(clientssl), X509_V_ERR_RPK_UNTRUSTED))
+        goto end;
+
     testresult = 1;
 
  end:
@@ -11083,7 +11099,7 @@ int setup_tests(void)
 #endif
 #ifndef OPENSSL_NO_TLS1_3
     ADD_ALL_TESTS(test_pluggable_group, 2);
-    ADD_ALL_TESTS(test_pluggable_signature, 2);
+    ADD_ALL_TESTS(test_pluggable_signature, 4);
 #endif
 #ifndef OPENSSL_NO_TLS1_2
     ADD_TEST(test_ssl_dup);
index 311f0c205f36fe4f9c59e5bf3b6ceac3f0969a9d..d3298ab4c6860c86fc77c3d0514f580a364bf043 100644 (file)
@@ -5514,3 +5514,6 @@ ASN1_item_unpack_ex                     ? 3_2_0   EXIST::FUNCTION:
 PKCS12_SAFEBAG_get1_cert_ex             ?      3_2_0   EXIST::FUNCTION:
 PKCS12_SAFEBAG_get1_crl_ex              ?      3_2_0   EXIST::FUNCTION:
 EC_GROUP_to_params                      ?      3_2_0   EXIST::FUNCTION:EC
+X509_STORE_CTX_init_rpk                 ?      3_2_0   EXIST::FUNCTION:
+X509_STORE_CTX_get0_rpk                 ?      3_2_0   EXIST::FUNCTION:
+X509_STORE_CTX_set0_rpk                 ?      3_2_0   EXIST::FUNCTION:
index f697f31114aaeb64382bbd25526dba8eb0ee7531..6bb916d63e5690cbe1a03f19208095c9342080f3 100644 (file)
@@ -544,3 +544,17 @@ SSL_net_write_desired                   ?  3_2_0   EXIST::FUNCTION:
 SSL_shutdown_ex                         ?      3_2_0   EXIST::FUNCTION:
 SSL_stream_conclude                     ?      3_2_0   EXIST::FUNCTION:
 SSL_inject_net_dgram                    ?      3_2_0   EXIST::FUNCTION:QUIC
+SSL_get0_peer_rpk                       ?      3_2_0   EXIST::FUNCTION:
+SSL_SESSION_get0_peer_rpk               ?      3_2_0   EXIST::FUNCTION:
+SSL_set1_client_cert_type               ?      3_2_0   EXIST::FUNCTION:
+SSL_get0_client_cert_type               ?      3_2_0   EXIST::FUNCTION:
+SSL_set1_server_cert_type               ?      3_2_0   EXIST::FUNCTION:
+SSL_get0_server_cert_type               ?      3_2_0   EXIST::FUNCTION:
+SSL_CTX_set1_client_cert_type           ?      3_2_0   EXIST::FUNCTION:
+SSL_CTX_get0_client_cert_type           ?      3_2_0   EXIST::FUNCTION:
+SSL_CTX_set1_server_cert_type           ?      3_2_0   EXIST::FUNCTION:
+SSL_CTX_get0_server_cert_type           ?      3_2_0   EXIST::FUNCTION:
+SSL_get_negotiated_client_cert_type     ?      3_2_0   EXIST::FUNCTION:
+SSL_get_negotiated_server_cert_type     ?      3_2_0   EXIST::FUNCTION:
+SSL_add_expected_rpk                    ?      3_2_0   EXIST::FUNCTION:
+d2i_SSL_SESSION_ex                      ?      3_2_0   EXIST::FUNCTION:
index 648d986342cd9e8c4a1f219e999ca4e012c4fb53..21e04a5cbc35bf1fe36c9514d6525994ae5b8a7e 100644 (file)
@@ -75,6 +75,8 @@ use constant {
     EXT_USE_SRTP => 14,
     EXT_ALPN => 16,
     EXT_SCT => 18,
+    EXT_CLIENT_CERT_TYPE => 19,
+    EXT_SERVER_CERT_TYPE => 20,
     EXT_PADDING => 21,
     EXT_ENCRYPT_THEN_MAC => 22,
     EXT_EXTENDED_MASTER_SECRET => 23,