From a9e1c50bb09a110d4774e6710f9322344684fa2d Mon Sep 17 00:00:00 2001 From: Ben Laurie Date: Wed, 30 May 2012 10:10:58 +0000 Subject: [PATCH 1/1] RFC 5878 support. --- CHANGES | 3 + apps/s_apps.h | 4 + apps/s_cb.c | 26 +++--- apps/s_client.c | 30 +++++++ apps/s_server.c | 51 +++++++++++- ssl/s23_clnt.c | 2 + ssl/s3_clnt.c | 140 ++++++++++++++++++++++++++++++++- ssl/s3_lib.c | 11 +++ ssl/s3_srvr.c | 116 ++++++++++++++++++++++++++- ssl/ssl.h | 39 ++++++++- ssl/ssl3.h | 22 +++++- ssl/ssl_cert.c | 20 +++++ ssl/ssl_err.c | 12 +++ ssl/ssl_lib.c | 79 +++++++++++++------ ssl/ssl_locl.h | 15 ++++ ssl/ssl_rsa.c | 120 ++++++++++++++++++++++++++-- ssl/ssl_sess.c | 11 +++ ssl/t1_lib.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++- ssl/tls1.h | 15 ++++ 19 files changed, 864 insertions(+), 57 deletions(-) diff --git a/CHANGES b/CHANGES index 7cca7f00a7..ec9291002b 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) RFC 5878 support. + [Emilia Kasper, Adam Langley, Ben Laurie (Google)] + *) Support for automatic EC temporary key parameter selection. If enabled the most preferred EC parameters are automatically used instead of hardcoded fixed parameters. Now a server just has to call: diff --git a/apps/s_apps.h b/apps/s_apps.h index 5de65329a9..4effcd21d7 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -156,6 +156,10 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, STACK_OF(X509) *chain); +# ifndef OPENSSL_NO_TLSEXT +int set_cert_key_and_authz(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, + unsigned char *authz, size_t authz_length); +# endif int ssl_print_sigalgs(BIO *out, SSL *s); int ssl_print_curves(BIO *out, SSL *s); #endif diff --git a/apps/s_cb.c b/apps/s_cb.c index b21a4283df..c07066b6b6 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -237,8 +237,8 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) /* If we are using DSA, we can copy the parameters from * the private key */ - - + + /* Now we know that a key and cert have been set against * the SSL context */ if (!SSL_CTX_check_private_key(ctx)) @@ -251,9 +251,9 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) } int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, - STACK_OF(X509) *chain) + STACK_OF(X509) *chain) { - if (cert == NULL) + if (cert == NULL) return 1; if (SSL_CTX_use_certificate(ctx,cert) <= 0) { @@ -261,16 +261,16 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, ERR_print_errors(bio_err); return 0; } - if (SSL_CTX_use_PrivateKey(ctx,key) <= 0) - { - BIO_printf(bio_err,"error setting private key\n"); - ERR_print_errors(bio_err); - return 0; - } - - /* Now we know that a key and cert have been set against - * the SSL context */ + if (SSL_CTX_use_PrivateKey(ctx,key) <= 0) + { + BIO_printf(bio_err,"error setting private key\n"); + ERR_print_errors(bio_err); + return 0; + } + + /* Now we know that a key and cert have been set against + * the SSL context */ if (!SSL_CTX_check_private_key(ctx)) { BIO_printf(bio_err,"Private key does not match the certificate public key\n"); diff --git a/apps/s_client.c b/apps/s_client.c index 16f1ac37db..8cbb46e540 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -202,6 +202,7 @@ static int c_debug=0; #ifndef OPENSSL_NO_TLSEXT static int c_tlsextdebug=0; static int c_status_req=0; +static int c_proof_debug=0; #endif static int c_msg=0; static int c_showcerts=0; @@ -213,6 +214,7 @@ static void sc_usage(void); static void print_stuff(BIO *berr,SSL *con,int full); #ifndef OPENSSL_NO_TLSEXT static int ocsp_resp_cb(SSL *s, void *arg); +static int audit_proof_cb(SSL *s, void *arg); #endif static BIO *bio_c_out=NULL; static int c_quiet=0; @@ -357,6 +359,7 @@ static void sc_usage(void) BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n"); BIO_printf(bio_err," -status - request certificate status from server\n"); BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); + BIO_printf(bio_err," -proof_debug - request an audit proof and print its hex dump\n"); # ifndef OPENSSL_NO_NEXTPROTONEG BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); # endif @@ -731,6 +734,8 @@ int MAIN(int argc, char **argv) c_tlsextdebug=1; else if (strcmp(*argv,"-status") == 0) c_status_req=1; + else if (strcmp(*argv,"-proof_debug") == 0) + c_proof_debug=1; #endif #ifdef WATT32 else if (strcmp(*argv,"-wdebug") == 0) @@ -1212,6 +1217,9 @@ bad: } #endif + if (c_proof_debug) + SSL_CTX_set_tlsext_authz_server_audit_proof_cb(ctx, + audit_proof_cb); #endif con=SSL_new(ctx); @@ -2147,4 +2155,26 @@ static int ocsp_resp_cb(SSL *s, void *arg) return 1; } +static int audit_proof_cb(SSL *s, void *arg) + { + const unsigned char *proof; + size_t proof_len; + size_t i; + SSL_SESSION *sess = SSL_get_session(s); + + proof = SSL_SESSION_get_tlsext_authz_server_audit_proof(sess, + &proof_len); + if (proof != NULL) + { + BIO_printf(bio_c_out, "Audit proof: "); + for (i = 0; i < proof_len; ++i) + BIO_printf(bio_c_out, "%02X", proof[i]); + BIO_printf(bio_c_out, "\n"); + } + else + { + BIO_printf(bio_c_out, "No audit proof found.\n"); + } + return 1; + } #endif diff --git a/apps/s_server.c b/apps/s_server.c index bb791e08e7..762757bf00 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -313,6 +313,12 @@ static long socket_mtu; static int cert_chain = 0; #endif +#ifndef OPENSSL_NO_TLSEXT +static BIO *authz_in = NULL; +static const char *s_authz_file = NULL; +static unsigned char *authz = NULL; +static size_t authz_length; +#endif #ifndef OPENSSL_NO_PSK static char *psk_identity="Client_identity"; @@ -473,6 +479,7 @@ static void sv_usage(void) BIO_printf(bio_err," -Verify arg - turn on peer certificate verification, must have a cert.\n"); BIO_printf(bio_err," -cert arg - certificate file to use\n"); BIO_printf(bio_err," (default is %s)\n",TEST_CERT); + BIO_printf(bio_err," -authz arg - binary authz file for certificate\n"); BIO_printf(bio_err," -crl_check - check the peer certificate has not been revoked by its CA.\n" \ " The CRL(s) are appended to the certificate file\n"); BIO_printf(bio_err," -crl_check_all - check the peer certificate has not been revoked by its CA\n" \ @@ -1044,6 +1051,13 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; s_cert_file= *(++argv); } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv,"-authz") == 0) + { + if (--argc < 1) goto bad; + s_authz_file = *(++argv); + } +#endif else if (strcmp(*argv,"-certform") == 0) { if (--argc < 1) goto bad; @@ -1490,7 +1504,34 @@ bad: next_proto.data = NULL; } # endif -#endif + if (s_authz_file != NULL) + { + /* Allow authzs up to 64KB bytes. */ + static const size_t authz_limit = 65536; + + authz_in = BIO_new(BIO_s_file_internal()); + if (authz_in == NULL) + { + ERR_print_errors(bio_err); + goto end; + } + + if (BIO_read_filename(authz_in, s_authz_file) <= 0) + { + ERR_print_errors(bio_err); + goto end; + } + authz = OPENSSL_malloc(authz_limit); + authz_length = BIO_read(authz_in, authz, authz_limit); + if (authz_length == authz_limit || authz_length <= 0) + { + BIO_printf(bio_err, "authz too large\n"); + goto end; + } + BIO_free(authz_in); + authz_in = NULL; + } +#endif /* OPENSSL_NO_TLSEXT */ } @@ -1789,6 +1830,10 @@ bad: if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain)) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (authz != NULL && !SSL_CTX_use_authz(ctx, authz, authz_length)) + goto end; +#endif #ifndef OPENSSL_NO_TLSEXT if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL)) goto end; @@ -1983,6 +2028,10 @@ end: X509_free(s_cert2); if (s_key2) EVP_PKEY_free(s_key2); + if (authz != NULL) + OPENSSL_free(authz); + if (authz_in != NULL) + BIO_free(authz_in); #endif if (bio_s_out != NULL) { diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 47673e740a..807dd0ba26 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -340,6 +340,8 @@ static int ssl23_client_hello(SSL *s) if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL) ssl2_compat = 0; #endif + if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL) + ssl2_compat = 0; } #endif diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index cd4f0ad468..e8fe968e59 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -307,10 +307,27 @@ int ssl3_connect(SSL *s) #endif } else - s->state=SSL3_ST_CR_CERT_A; + { +#ifndef OPENSSL_NO_TLSEXT + /* The server hello indicated that + * an audit proof would follow. */ + if (s->s3->tlsext_authz_server_promised) + s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A; + else +#endif + s->state=SSL3_ST_CR_CERT_A; + } s->init_num=0; break; - +#ifndef OPENSSL_NO_TLSEXT + case SSL3_ST_CR_SUPPLEMENTAL_DATA_A: + case SSL3_ST_CR_SUPPLEMENTAL_DATA_B: + ret = tls1_get_server_supplemental_data(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_CERT_A; + s->init_num = 0; + break; +#endif case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: #ifndef OPENSSL_NO_TLSEXT @@ -1231,8 +1248,22 @@ int ssl3_get_server_certificate(SSL *s) s->session->verify_result = s->verify_result; x=NULL; - ret=1; +#ifndef OPENSSL_NO_TLSEXT + /* Check the audit proof. */ + if (s->ctx->tlsext_authz_server_audit_proof_cb) + { + ret = s->ctx->tlsext_authz_server_audit_proof_cb(s, + s->ctx->tlsext_authz_server_audit_proof_cb_arg); + if (ret <= 0) + { + al = SSL_AD_BAD_CERTIFICATE; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_INVALID_AUDIT_PROOF); + goto f_err; + } + } +#endif + ret=1; if (0) { f_err: @@ -3432,3 +3463,106 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) i = s->ctx->client_cert_cb(s,px509,ppkey); return i; } + +#ifndef OPENSSL_NO_TLSEXT +int tls1_get_server_supplemental_data(SSL *s) + { + int al; + int ok; + unsigned long supp_data_len, authz_data_len; + long n; + unsigned short supp_data_type, authz_data_type, proof_len; + const unsigned char *p; + unsigned char *new_proof; + + n=s->method->ssl_get_message(s, + SSL3_ST_CR_SUPPLEMENTAL_DATA_A, + SSL3_ST_CR_SUPPLEMENTAL_DATA_B, + SSL3_MT_SUPPLEMENTAL_DATA, + /* use default limit */ + TLSEXT_MAXLEN_supplemental_data, + &ok); + + if (!ok) return((int)n); + + p = (unsigned char *)s->init_msg; + + /* The message cannot be empty */ + if (n < 3) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* Length of supplemental data */ + n2l3(p,supp_data_len); + n -= 3; + /* We must have at least one supplemental data entry + * with type (1 byte) and length (2 bytes). */ + if (supp_data_len != (unsigned long) n || n < 4) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* Supplemental data type: must be authz_data */ + n2s(p,supp_data_type); + n -= 2; + if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data) + { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE); + goto f_err; + } + /* Authz data length */ + n2s(p, authz_data_len); + n -= 2; + if (authz_data_len != (unsigned long) n || n < 1) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* Authz data type: must be audit_proof */ + authz_data_type = *(p++); + n -= 1; + if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_AUTHZ_DATA_TYPE); + goto f_err; + } + /* We have a proof: read its length */ + if (n < 2) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + n2s(p, proof_len); + n -= 2; + if (proof_len != (unsigned long) n) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* Store the proof */ + new_proof = OPENSSL_realloc(s->session->audit_proof, + proof_len); + if (new_proof == NULL) + { + SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,ERR_R_MALLOC_FAILURE); + return 0; + } + s->session->audit_proof_length = proof_len; + s->session->audit_proof = new_proof; + memcpy(s->session->audit_proof, p, proof_len); + + /* Got the proof, but can't verify it yet. */ + return 1; +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + return -1; + } +#endif diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 0456230fd3..9653de6eea 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3684,6 +3684,11 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) case SSL_CTRL_SET_ECDH_AUTO: ctx->cert->ecdh_tmp_auto = larg; break; + + case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG: + ctx->tlsext_authz_server_audit_proof_cb_arg = parg; + break; + #endif /* !OPENSSL_NO_TLSEXT */ /* A Thawte special :-) */ @@ -3793,6 +3798,12 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) ctx->srp_ctx.SRP_give_srp_client_pwd_callback=(char *(*)(SSL *,void *))fp; break; #endif + + case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB: + ctx->tlsext_authz_server_audit_proof_cb = + (int (*)(SSL *, void *))fp; + break; + #endif case SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB: { diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 632b924ef2..ba324848c1 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -403,9 +403,30 @@ int ssl3_accept(SSL *s) s->state=SSL3_ST_SW_CHANGE_A; #endif else - s->state=SSL3_ST_SW_CERT_A; - s->init_num=0; +#ifndef OPENSSL_NO_TLSEXT + s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A; +#else + s->state = SSL3_ST_SW_CERT_A; +#endif + s->init_num = 0; + break; + +#ifndef OPENSSL_NO_TLSEXT + case SSL3_ST_SW_SUPPLEMENTAL_DATA_A: + case SSL3_ST_SW_SUPPLEMENTAL_DATA_B: + /* We promised to send an audit proof in the hello. */ + if (s->s3->tlsext_authz_promised_to_client) + { + ret = tls1_send_server_supplemental_data(s); + if (ret <= 0) goto end; + } + else + skip = 1; + + s->state = SSL3_ST_SW_CERT_A; + s->init_num = 0; break; +#endif case SSL3_ST_SW_CERT_A: case SSL3_ST_SW_CERT_B: @@ -3629,4 +3650,95 @@ int ssl3_get_next_proto(SSL *s) return 1; } # endif + +int tls1_send_server_supplemental_data(SSL *s) + { + size_t length = 0; + const unsigned char *authz, *orig_authz; + unsigned char *p; + size_t authz_length, i; + + if (s->state != SSL3_ST_SW_SUPPLEMENTAL_DATA_A) + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + + orig_authz = authz = ssl_get_authz_data(s, &authz_length); + if (authz == NULL) + { + /* This should never occur. */ + return 0; + } + + /* First we walk over the authz data to see how long the handshake + * message will be. */ + for (i = 0; i < authz_length; i++) + { + unsigned short len; + unsigned char type; + + type = *(authz++); + n2s(authz, len); + + if (memchr(s->s3->tlsext_authz_client_types, + type, + s->s3->tlsext_authz_client_types_len) != NULL) + length += 1 /* authz type */ + 2 /* length */ + len; + + authz += len; + i += len; + } + + length += 1 /* handshake type */ + + 3 /* handshake length */ + + 3 /* supplemental data length */ + + 2 /* supplemental entry type */ + + 2 /* supplemental entry length */; + + if (!BUF_MEM_grow_clean(s->init_buf, length)) + { + SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB); + return 0; + } + + p = (unsigned char *)s->init_buf->data; + *(p++) = SSL3_MT_SUPPLEMENTAL_DATA; + /* Handshake length */ + l2n3(length - 4, p); + /* Length of supplemental data */ + l2n3(length - 7, p); + /* Supplemental data type */ + s2n(TLSEXT_SUPPLEMENTALDATATYPE_authz_data, p); + /* Its length */ + s2n(length - 11, p); + + authz = orig_authz; + + /* Walk over the authz again and append the selected elements. */ + for (i = 0; i < authz_length; i++) + { + unsigned short len; + unsigned char type; + + type = *(authz++); + n2s(authz, len); + + if (memchr(s->s3->tlsext_authz_client_types, + type, + s->s3->tlsext_authz_client_types_len) != NULL) + { + *(p++) = type; + s2n(len, p); + memcpy(p, authz, len); + p += len; + } + + authz += len; + i += len; + } + + s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B; + s->init_num = length; + s->init_off = 0; + + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + } #endif diff --git a/ssl/ssl.h b/ssl/ssl.h index 352e91b32a..31eccf904d 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -539,11 +539,18 @@ struct ssl_session_st #endif /* OPENSSL_NO_EC */ /* RFC4507 info */ unsigned char *tlsext_tick; /* Session ticket */ - size_t tlsext_ticklen; /* Session ticket length */ + size_t tlsext_ticklen; /* Session ticket length */ long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ #endif #ifndef OPENSSL_NO_SRP char *srp_username; +#endif +#ifndef OPENSSL_NO_TLSEXT + /* Used by client: the proof for this session. + * We store it outside the sess_cert structure, since the proof + * is received before the certificate. */ + unsigned char *audit_proof; + size_t audit_proof_length; #endif }; @@ -977,7 +984,7 @@ struct ssl_ctx_st void *next_proto_select_cb_arg; # endif /* SRTP profiles we are willing to do from RFC 5764 */ - STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; #endif /* Callback for disabling session caching and ticket support * on a session basis, depending on the chosen cipher. */ @@ -989,6 +996,8 @@ struct ssl_ctx_st size_t tlsext_ellipticcurvelist_length; unsigned char *tlsext_ellipticcurvelist; #endif /* OPENSSL_NO_EC */ + int (*tlsext_authz_server_audit_proof_cb)(SSL *s, void *arg); + void *tlsext_authz_server_audit_proof_cb_arg; }; #endif @@ -1608,7 +1617,10 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING 86 #define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS 87 #endif -#endif +/* Callback for verifying audit proofs (client only) */ +#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB 95 +#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG 96 +#endif /* OPENSSL_NO_TLSEXT */ #define DTLS_CTRL_GET_TIMEOUT 73 #define DTLS_CTRL_HANDLE_TIMEOUT 74 @@ -1768,6 +1780,11 @@ int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len); int SSL_use_certificate(SSL *ssl, X509 *x); int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); +#ifndef OPENSSL_NO_TLSEXT +int SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz, size_t authz_length); +int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length); +#endif + #ifndef OPENSSL_NO_STDIO int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); @@ -1812,6 +1829,10 @@ int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses); #ifndef OPENSSL_NO_BIO int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses); #endif +#ifndef OPENSSL_NO_TLSEXT +unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s, + size_t *proof_length); +#endif void SSL_SESSION_free(SSL_SESSION *ses); int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp); int SSL_set_session(SSL *to, SSL_SESSION *session); @@ -2115,6 +2136,7 @@ void ERR_load_SSL_strings(void); /* Error codes for the SSL functions. */ /* Function codes. */ +#define SSL_F_AUTHZ_VALIDATE 323 #define SSL_F_CLIENT_CERTIFICATE 100 #define SSL_F_CLIENT_FINISHED 167 #define SSL_F_CLIENT_HELLO 101 @@ -2260,6 +2282,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219 #define SSL_F_SSL_CTX_SET_SSL_VERSION 170 #define SSL_F_SSL_CTX_SET_TRUST 229 +#define SSL_F_SSL_CTX_USE_AUTHZ 324 #define SSL_F_SSL_CTX_USE_CERTIFICATE 171 #define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 #define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220 @@ -2274,6 +2297,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_DO_HANDSHAKE 180 #define SSL_F_SSL_GET_NEW_SESSION 181 #define SSL_F_SSL_GET_PREV_SESSION 217 +#define SSL_F_SSL_GET_SERVER_CERT_INDEX 329 #define SSL_F_SSL_GET_SERVER_SEND_PKEY 182 #define SSL_F_SSL_GET_SIGN_PKEY 183 #define SSL_F_SSL_INIT_WBIO_BUFFER 184 @@ -2297,6 +2321,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_SESSION_PRINT_FP 190 #define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312 #define SSL_F_SSL_SESS_CERT_NEW 225 +#define SSL_F_SSL_SET_AUTHZ 325 #define SSL_F_SSL_SET_CERT 191 #define SSL_F_SSL_SET_CIPHER_LIST 271 #define SSL_F_SSL_SET_FD 192 @@ -2313,6 +2338,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243 #define SSL_F_SSL_UNDEFINED_FUNCTION 197 #define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244 +#define SSL_F_SSL_USE_AUTHZ 328 #define SSL_F_SSL_USE_CERTIFICATE 198 #define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 #define SSL_F_SSL_USE_CERTIFICATE_FILE 200 @@ -2330,16 +2356,19 @@ void ERR_load_SSL_strings(void); #define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274 #define SSL_F_TLS1_ENC 210 #define SSL_F_TLS1_EXPORT_KEYING_MATERIAL 314 +#define SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA 326 #define SSL_F_TLS1_HEARTBEAT 315 #define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275 #define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276 #define SSL_F_TLS1_PRF 284 +#define SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA 327 #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 #define SSL_F_WRITE_PENDING 212 /* Reason codes. */ #define SSL_R_APP_DATA_IN_HANDSHAKE 100 #define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 +#define SSL_R_AUTHZ_DATA_TOO_LARGE 375 #define SSL_R_BAD_ALERT_RECORD 101 #define SSL_R_BAD_AUTHENTICATION_TYPE 102 #define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 @@ -2428,6 +2457,8 @@ void ERR_load_SSL_strings(void); #define SSL_R_HTTP_REQUEST 156 #define SSL_R_ILLEGAL_PADDING 283 #define SSL_R_INCONSISTENT_COMPRESSION 340 +#define SSL_R_INVALID_AUDIT_PROOF 371 +#define SSL_R_INVALID_AUTHZ_DATA 374 #define SSL_R_INVALID_CHALLENGE_LENGTH 158 #define SSL_R_INVALID_COMMAND 280 #define SSL_R_INVALID_COMPRESSION_ALGORITHM 341 @@ -2607,6 +2638,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNEXPECTED_RECORD 245 #define SSL_R_UNINITIALIZED 276 #define SSL_R_UNKNOWN_ALERT_TYPE 246 +#define SSL_R_UNKNOWN_AUTHZ_DATA_TYPE 372 #define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 #define SSL_R_UNKNOWN_CIPHER_RETURNED 248 #define SSL_R_UNKNOWN_CIPHER_TYPE 249 @@ -2617,6 +2649,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253 #define SSL_R_UNKNOWN_SSL_VERSION 254 #define SSL_R_UNKNOWN_STATE 255 +#define SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE 373 #define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338 #define SSL_R_UNSUPPORTED_CIPHER 256 #define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 4e72c1749b..84198ff501 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -540,6 +540,22 @@ typedef struct ssl3_state_st our peer. */ int next_proto_neg_seen; #endif + +#ifndef OPENSSL_NO_TLSEXT + /* tlsext_authz_client_types contains an array of supported authz + * types, as advertised by the client. The array is sorted and + * does not contain any duplicates. */ + unsigned char *tlsext_authz_client_types; + size_t tlsext_authz_client_types_len; + /* tlsext_authz_promised_to_client is true iff we're a server and we + * echoed the client's supplemental data extension and therefore must + * send a supplemental data handshake message. */ + char tlsext_authz_promised_to_client; + /* tlsext_authz_server_promised is true iff we're a client and the + * server echoed our server_authz extension and therefore must send us + * a supplemental data handshake message. */ + char tlsext_authz_server_promised; +#endif } SSL3_STATE; #endif @@ -568,6 +584,8 @@ typedef struct ssl3_state_st #define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT) #define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT) #define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT) +#define SSL3_ST_CR_SUPPLEMENTAL_DATA_A (0x210|SSL_ST_CONNECT) +#define SSL3_ST_CR_SUPPLEMENTAL_DATA_B (0x211|SSL_ST_CONNECT) /* write to server */ #define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT) #define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT) @@ -647,6 +665,8 @@ typedef struct ssl3_state_st #define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A (0x220|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B (0x221|SSL_ST_ACCEPT) #define SSL3_MT_HELLO_REQUEST 0 #define SSL3_MT_CLIENT_HELLO 1 @@ -660,6 +680,7 @@ typedef struct ssl3_state_st #define SSL3_MT_CLIENT_KEY_EXCHANGE 16 #define SSL3_MT_FINISHED 20 #define SSL3_MT_CERTIFICATE_STATUS 22 +#define SSL3_MT_SUPPLEMENTAL_DATA 23 #ifndef OPENSSL_NO_NEXTPROTONEG #define SSL3_MT_NEXT_PROTO 67 #endif @@ -682,4 +703,3 @@ typedef struct ssl3_state_st } #endif #endif - diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 222f703284..fcf462d41a 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -334,6 +334,22 @@ CERT *ssl_cert_dup(CERT *cert) CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); } } + if (cert->pkeys[i].authz != NULL) + { + /* Just copy everything. */ + ret->pkeys[i].authz_length = + cert->pkeys[i].authz_length; + ret->pkeys[i].authz = + OPENSSL_malloc(ret->pkeys[i].authz_length); + if (ret->pkeys[i].authz == NULL) + { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + return(NULL); + } + memcpy(ret->pkeys[i].authz, + cert->pkeys[i].authz, + cert->pkeys[i].authz_length); + } } ret->references=1; @@ -421,6 +437,10 @@ void ssl_cert_free(CERT *c) #if 0 if (c->pkeys[i].publickey != NULL) EVP_PKEY_free(c->pkeys[i].publickey); +#endif +#ifndef OPENSSL_NO_TLSEXT + if (c->pkeys[i].authz != NULL) + OPENSSL_free(c->pkeys[i].authz); #endif } if (c->sigalgs) diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 0a43d249e8..ce004558a2 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -70,6 +70,7 @@ static ERR_STRING_DATA SSL_str_functs[]= { +{ERR_FUNC(SSL_F_AUTHZ_VALIDATE), "AUTHZ_VALIDATE"}, {ERR_FUNC(SSL_F_CLIENT_CERTIFICATE), "CLIENT_CERTIFICATE"}, {ERR_FUNC(SSL_F_CLIENT_FINISHED), "CLIENT_FINISHED"}, {ERR_FUNC(SSL_F_CLIENT_HELLO), "CLIENT_HELLO"}, @@ -215,6 +216,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT), "SSL_CTX_set_session_id_context"}, {ERR_FUNC(SSL_F_SSL_CTX_SET_SSL_VERSION), "SSL_CTX_set_ssl_version"}, {ERR_FUNC(SSL_F_SSL_CTX_SET_TRUST), "SSL_CTX_set_trust"}, +{ERR_FUNC(SSL_F_SSL_CTX_USE_AUTHZ), "SSL_CTX_use_authz"}, {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE), "SSL_CTX_use_certificate"}, {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1), "SSL_CTX_use_certificate_ASN1"}, {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE), "SSL_CTX_use_certificate_chain_file"}, @@ -229,6 +231,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"}, {ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "SSL_GET_NEW_SESSION"}, {ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION), "SSL_GET_PREV_SESSION"}, +{ERR_FUNC(SSL_F_SSL_GET_SERVER_CERT_INDEX), "SSL_GET_SERVER_CERT_INDEX"}, {ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_PKEY), "SSL_GET_SERVER_SEND_PKEY"}, {ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "SSL_GET_SIGN_PKEY"}, {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"}, @@ -252,6 +255,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP), "SSL_SESSION_print_fp"}, {ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT), "SSL_SESSION_set1_id_context"}, {ERR_FUNC(SSL_F_SSL_SESS_CERT_NEW), "SSL_SESS_CERT_NEW"}, +{ERR_FUNC(SSL_F_SSL_SET_AUTHZ), "SSL_SET_AUTHZ"}, {ERR_FUNC(SSL_F_SSL_SET_CERT), "SSL_SET_CERT"}, {ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST), "SSL_set_cipher_list"}, {ERR_FUNC(SSL_F_SSL_SET_FD), "SSL_set_fd"}, @@ -268,6 +272,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_UNDEFINED_CONST_FUNCTION), "SSL_UNDEFINED_CONST_FUNCTION"}, {ERR_FUNC(SSL_F_SSL_UNDEFINED_FUNCTION), "SSL_UNDEFINED_FUNCTION"}, {ERR_FUNC(SSL_F_SSL_UNDEFINED_VOID_FUNCTION), "SSL_UNDEFINED_VOID_FUNCTION"}, +{ERR_FUNC(SSL_F_SSL_USE_AUTHZ), "SSL_use_authz"}, {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE), "SSL_use_certificate"}, {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_ASN1), "SSL_use_certificate_ASN1"}, {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_FILE), "SSL_use_certificate_file"}, @@ -285,10 +290,12 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, {ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), "TLS1_EXPORT_KEYING_MATERIAL"}, +{ERR_FUNC(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA), "TLS1_GET_SERVER_SUPPLEMENTAL_DATA"}, {ERR_FUNC(SSL_F_TLS1_HEARTBEAT), "SSL_F_TLS1_HEARTBEAT"}, {ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"}, +{ERR_FUNC(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA), "TLS1_SEND_SERVER_SUPPLEMENTAL_DATA"}, {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, {0,NULL} @@ -298,6 +305,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= { {ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE) ,"app data in handshake"}, {ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),"attempt to reuse session in different context"}, +{ERR_REASON(SSL_R_AUTHZ_DATA_TOO_LARGE) ,"authz data too large"}, {ERR_REASON(SSL_R_BAD_ALERT_RECORD) ,"bad alert record"}, {ERR_REASON(SSL_R_BAD_AUTHENTICATION_TYPE),"bad authentication type"}, {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC),"bad change cipher spec"}, @@ -386,6 +394,8 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_HTTP_REQUEST) ,"http request"}, {ERR_REASON(SSL_R_ILLEGAL_PADDING) ,"illegal padding"}, {ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION),"inconsistent compression"}, +{ERR_REASON(SSL_R_INVALID_AUDIT_PROOF) ,"invalid audit proof"}, +{ERR_REASON(SSL_R_INVALID_AUTHZ_DATA) ,"invalid authz data"}, {ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"}, {ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"}, {ERR_REASON(SSL_R_INVALID_COMPRESSION_ALGORITHM),"invalid compression algorithm"}, @@ -565,6 +575,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_UNEXPECTED_RECORD) ,"unexpected record"}, {ERR_REASON(SSL_R_UNINITIALIZED) ,"uninitialized"}, {ERR_REASON(SSL_R_UNKNOWN_ALERT_TYPE) ,"unknown alert type"}, +{ERR_REASON(SSL_R_UNKNOWN_AUTHZ_DATA_TYPE),"unknown authz data type"}, {ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"}, {ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"}, {ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE) ,"unknown cipher type"}, @@ -575,6 +586,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"}, {ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION) ,"unknown ssl version"}, {ERR_REASON(SSL_R_UNKNOWN_STATE) ,"unknown state"}, +{ERR_REASON(SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE),"unknown supplemental data type"}, {ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"}, {ERR_REASON(SSL_R_UNSUPPORTED_CIPHER) ,"unsupported cipher"}, {ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 679894cb3d..cb098b3002 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2323,15 +2323,10 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) #endif /* THIS NEEDS CLEANING UP */ -CERT_PKEY *ssl_get_server_send_pkey(SSL *s) +static int ssl_get_server_cert_index(SSL *s) { - unsigned long alg_k,alg_a; - CERT *c; - int i; + unsigned long alg_k, alg_a; - c=s->cert; - ssl_set_cert_masks(c, s->s3->tmp.new_cipher); - alg_k = s->s3->tmp.new_cipher->algorithm_mkey; alg_a = s->s3->tmp.new_cipher->algorithm_auth; @@ -2348,42 +2343,53 @@ CERT_PKEY *ssl_get_server_send_pkey(SSL *s) * checks for SSL_kECDH before RSA * checks ensures the correct cert is chosen. */ - i=SSL_PKEY_ECC; + return SSL_PKEY_ECC; } else if (alg_a & SSL_aECDSA) - { - i=SSL_PKEY_ECC; - } + return SSL_PKEY_ECC; else if (alg_k & SSL_kDHr) - i=SSL_PKEY_DH_RSA; + return SSL_PKEY_DH_RSA; else if (alg_k & SSL_kDHd) - i=SSL_PKEY_DH_DSA; + return SSL_PKEY_DH_DSA; else if (alg_a & SSL_aDSS) - i=SSL_PKEY_DSA_SIGN; + return SSL_PKEY_DSA_SIGN; else if (alg_a & SSL_aRSA) { - if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL) - i=SSL_PKEY_RSA_SIGN; + if (s->cert->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL) + return SSL_PKEY_RSA_SIGN; else - i=SSL_PKEY_RSA_ENC; + return SSL_PKEY_RSA_ENC; } else if (alg_a & SSL_aKRB5) - { /* VRS something else here? */ - return(NULL); - } + return -1; else if (alg_a & SSL_aGOST94) - i=SSL_PKEY_GOST94; + return SSL_PKEY_GOST94; else if (alg_a & SSL_aGOST01) - i=SSL_PKEY_GOST01; + return SSL_PKEY_GOST01; else /* if (alg_a & SSL_aNULL) */ { - SSLerr(SSL_F_SSL_GET_SERVER_SEND_PKEY,ERR_R_INTERNAL_ERROR); - return(NULL); + SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX,ERR_R_INTERNAL_ERROR); + return -1; } - if (c->pkeys[i].x509 == NULL) return(NULL); + } + +CERT_PKEY *ssl_get_server_send_pkey(SSL *s) + { + CERT *c; + int i; - return(&c->pkeys[i]); + c = s->cert; + ssl_set_cert_masks(c, s->s3->tmp.new_cipher); + + i = ssl_get_server_cert_index(s); + + /* This may or may not be an error. */ + if (i < 0) + return NULL; + + /* May be NULL. */ + return &c->pkeys[i]; } EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd) @@ -2418,6 +2424,27 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd) return c->pkeys[idx].privatekey; } +#ifndef OPENSSL_NO_TLSEXT +unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length) + { + CERT *c; + int i; + + c = s->cert; + i = ssl_get_server_cert_index(s); + + if (i == -1) + return NULL; + + *authz_length = 0; + if (c->pkeys[i].authz == NULL) + return(NULL); + *authz_length = c->pkeys[i].authz_length; + + return c->pkeys[i].authz; + } +#endif + void ssl_update_cache(SSL *s,int mode) { int i; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index b83b174da9..d0167e8283 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -474,6 +474,15 @@ typedef struct cert_pkey_st const EVP_MD *digest; /* Chain for this certificate */ STACK_OF(X509) *chain; +#ifndef OPENSSL_NO_TLSEXT + /* authz/authz_length contain authz data for this certificate. The data + * is in wire format, specifically it's a series of records like: + * uint8_t authz_type; // (RFC 5878, AuthzDataFormat) + * uint16_t length; + * uint8_t data[length]; */ + unsigned char *authz; + size_t authz_length; +#endif } CERT_PKEY; typedef struct cert_st @@ -856,6 +865,7 @@ int ssl_undefined_function(SSL *s); int ssl_undefined_void_function(void); int ssl_undefined_const_function(const SSL *s); CERT_PKEY *ssl_get_server_send_pkey(SSL *); +unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length); EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd); int ssl_cert_type(X509 *x,EVP_PKEY *pkey); void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher); @@ -1125,6 +1135,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int ssl_prepare_clienthello_tlsext(SSL *s); int ssl_prepare_serverhello_tlsext(SSL *s); +/* server only */ +int tls1_send_server_supplemental_data(SSL *s); +/* client only */ +int tls1_get_server_supplemental_data(SSL *s); + #ifndef OPENSSL_NO_HEARTBEATS int tls1_heartbeat(SSL *s); int dtls1_heartbeat(SSL *s); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index b7c19051e9..855952d54c 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -66,6 +66,10 @@ static int ssl_set_cert(CERT *c, X509 *x509); static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); +#ifndef OPENSSL_NO_TLSEXT +static int ssl_set_authz(CERT *c, unsigned char *authz, + size_t authz_length); +#endif int SSL_use_certificate(SSL *ssl, X509 *x) { if (x == NULL) @@ -459,6 +463,15 @@ static int ssl_set_cert(CERT *c, X509 *x) X509_free(c->pkeys[i].x509); CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509); c->pkeys[i].x509=x; +#ifndef OPENSSL_NO_TLSEXT + /* Free the old authz data, if it exists. */ + if (c->pkeys[i].authz != NULL) + { + OPENSSL_free(c->pkeys[i].authz); + c->pkeys[i].authz = NULL; + c->pkeys[i].authz_length = 0; + } +#endif c->key= &(c->pkeys[i]); c->valid=0; @@ -725,7 +738,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ - in=BIO_new(BIO_s_file_internal()); + in = BIO_new(BIO_s_file_internal()); if (in == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB); @@ -738,14 +751,16 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) goto end; } - x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); + x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB); goto end; } - ret=SSL_CTX_use_certificate(ctx,x); + ret = SSL_CTX_use_certificate(ctx, x); + if (ERR_peek_error() != 0) ret = 0; /* Key/certificate mismatch doesn't imply ret==0 ... */ if (ret) @@ -757,13 +772,15 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) int r; unsigned long err; - if (ctx->extra_certs != NULL) + if (ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->extra_certs, X509_free); ctx->extra_certs = NULL; } - while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata)) + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != NULL) { r = SSL_CTX_add_extra_chain_cert(ctx, ca); @@ -792,3 +809,96 @@ end: return(ret); } #endif + +#ifndef OPENSSL_NO_TLSEXT +/* authz_validate returns true iff authz is well formed, i.e. that it meets the + * wire format as documented in the CERT_PKEY structure and that there are no + * duplicate entries. */ +static char authz_validate(const unsigned char *authz, size_t length) + { + unsigned char types_seen_bitmap[32]; + + if (!authz) + return 1; + + memset(types_seen_bitmap, 0, sizeof(types_seen_bitmap)); + + for (;;) + { + unsigned char type, byte, bit; + unsigned short len; + + if (!length) + return 1; + + type = *(authz++); + length--; + + byte = type / 8; + bit = type & 7; + if (types_seen_bitmap[byte] & (1 << bit)) + return 0; + types_seen_bitmap[byte] |= (1 << bit); + + if (length < 2) + return 0; + len = ((unsigned short) authz[0]) << 8 | + ((unsigned short) authz[1]); + authz += 2; + length -= 2; + + if (length < len) + return 0; + + authz += len; + length -= len; + } + } + +static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length) + { + CERT_PKEY *current_key = c->key; + if (current_key == NULL) + return 0; + if (!authz_validate(authz, authz_length)) + { + SSLerr(SSL_F_SSL_SET_AUTHZ,SSL_R_INVALID_AUTHZ_DATA); + return(0); + } + current_key->authz = OPENSSL_realloc(current_key->authz, authz_length); + current_key->authz_length = authz_length; + memcpy(current_key->authz, authz, authz_length); + return 1; + } + +int SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz, + size_t authz_length) + { + if (authz == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!ssl_cert_inst(&ctx->cert)) + { + SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_MALLOC_FAILURE); + return 0; + } + return ssl_set_authz(ctx->cert, authz, authz_length); + } + +int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length) + { + if (authz == NULL) + { + SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!ssl_cert_inst(&ssl->cert)) + { + SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_MALLOC_FAILURE); + return 0; + } + return ssl_set_authz(ssl->cert, authz, authz_length); + } +#endif /* OPENSSL_NO_TLSEXT */ diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 9e8f2e4ece..093ea60ae6 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -739,6 +739,8 @@ void SSL_SESSION_free(SSL_SESSION *ss) ss->tlsext_ellipticcurvelist_length = 0; if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist); #endif /* OPENSSL_NO_EC */ + if (ss->audit_proof != NULL) OPENSSL_free(ss->audit_proof); + ss->audit_proof_length = 0; #endif #ifndef OPENSSL_NO_PSK if (ss->psk_identity_hint != NULL) @@ -860,6 +862,15 @@ int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx, return 1; } +#ifndef OPENSSL_NO_TLSEXT +unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s, size_t *proof_length) + { + if (s->audit_proof != NULL) + *proof_length = s->audit_proof_length; + return s->audit_proof; + } +#endif + long SSL_CTX_set_timeout(SSL_CTX *s, long t) { long l; diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index f62a004cf2..12230e8ae1 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -642,6 +642,19 @@ int tls12_get_req_sig_algs(SSL *s, unsigned char *p) return (int)slen; } +/* byte_compare is a compare function for qsort(3) that compares bytes. */ +static int byte_compare(const void *in_a, const void *in_b) + { + unsigned char a = *((const unsigned char*) in_a); + unsigned char b = *((const unsigned char*) in_b); + + if (a > b) + return 1; + else if (a < b) + return -1; + return 0; +} + unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) { int extdatalen=0; @@ -983,7 +996,27 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret += el; } - if ((extdatalen = ret-p-2)== 0) + /* Add TLS extension Server_Authz_DataFormats to the ClientHello */ + /* 2 bytes for extension type */ + /* 2 bytes for extension length */ + /* 1 byte for the list length */ + /* 1 byte for the list (we only support audit proofs) */ + if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL) + { + size_t lenmax; + const unsigned short ext_len = 2; + const unsigned char list_len = 1; + + if ((lenmax = limit - ret - 6) < 0) return NULL; + + s2n(TLSEXT_TYPE_server_authz, ret); + /* Extension length: 2 bytes */ + s2n(ext_len, ret); + *(ret++) = list_len; + *(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof; + } + + if ((extdatalen = ret-p-2) == 0) return p; s2n(extdatalen,p); @@ -1170,6 +1203,75 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif + /* If the client supports authz then see whether we have any to offer + * to it. */ + if (s->s3->tlsext_authz_client_types_len) + { + size_t authz_length; + /* By now we already know the new cipher, so we can look ahead + * to see whether the cert we are going to send + * has any authz data attached to it. */ + const unsigned char* authz = ssl_get_authz_data(s, &authz_length); + const unsigned char* const orig_authz = authz; + size_t i; + unsigned authz_count = 0; + + /* The authz data contains a number of the following structures: + * uint8_t authz_type + * uint16_t length + * uint8_t data[length] + * + * First we walk over it to find the number of authz elements. */ + for (i = 0; i < authz_length; i++) + { + unsigned short length; + unsigned char type; + + type = *(authz++); + if (memchr(s->s3->tlsext_authz_client_types, + type, + s->s3->tlsext_authz_client_types_len) != NULL) + authz_count++; + + n2s(authz, length); + authz += length; + i += length; + } + + if (authz_count) + { + /* Add TLS extension server_authz to the ServerHello message + * 2 bytes for extension type + * 2 bytes for extension length + * 1 byte for the list length + * n bytes for the list */ + const unsigned short ext_len = 1 + authz_count; + + if ((long)(limit - ret - 4 - ext_len) < 0) return NULL; + s2n(TLSEXT_TYPE_server_authz, ret); + s2n(ext_len, ret); + *(ret++) = authz_count; + s->s3->tlsext_authz_promised_to_client = 1; + } + + authz = orig_authz; + for (i = 0; i < authz_length; i++) + { + unsigned short length; + unsigned char type; + + authz_count++; + type = *(authz++); + if (memchr(s->s3->tlsext_authz_client_types, + type, + s->s3->tlsext_authz_client_types_len) != NULL) + *(ret++) = type; + n2s(authz, length); + authz += length; + i += length; + } + } + if ((extdatalen = ret-p-2)== 0) return p; @@ -1650,9 +1752,67 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char return 0; } + else if (type == TLSEXT_TYPE_server_authz) + { + unsigned char *sdata = data; + unsigned char server_authz_dataformatlist_length; + + if (size == 0) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + + server_authz_dataformatlist_length = *(sdata++); + + if (server_authz_dataformatlist_length != size - 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + + /* Successful session resumption uses the same authz + * information as the original session so we ignore this + * in the case of a session resumption. */ + if (!s->hit) + { + size_t i; + s->s3->tlsext_authz_client_types = + OPENSSL_malloc(server_authz_dataformatlist_length); + if (!s->s3->tlsext_authz_client_types) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + s->s3->tlsext_authz_client_types_len = + server_authz_dataformatlist_length; + memcpy(s->s3->tlsext_authz_client_types, + sdata, + server_authz_dataformatlist_length); + + /* Sort the types in order to check for duplicates. */ + qsort(s->s3->tlsext_authz_client_types, + server_authz_dataformatlist_length, + 1 /* element size */, + byte_compare); + + for (i = 0; i < server_authz_dataformatlist_length; i++) + { + if (i > 0 && + s->s3->tlsext_authz_client_types[i] == + s->s3->tlsext_authz_client_types[i-1]) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + } + } + } + data+=size; } - + *p = data; ri_check: @@ -1916,7 +2076,46 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char return 0; } - data+=size; + else if (type == TLSEXT_TYPE_server_authz) + { + /* We only support audit proofs. It's an error to send + * an authz hello extension if the client + * didn't request a proof. */ + unsigned char *sdata = data; + unsigned char server_authz_dataformatlist_length; + + if (!s->ctx->tlsext_authz_server_audit_proof_cb) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + + if (!size) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + + server_authz_dataformatlist_length = *(sdata++); + if (server_authz_dataformatlist_length != size - 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + + /* We only support audit proofs, so a legal ServerHello + * authz list contains exactly one entry. */ + if (server_authz_dataformatlist_length != 1 || + sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + + s->s3->tlsext_authz_server_promised = 1; + } + + data += size; } if (data != d+n) diff --git a/ssl/tls1.h b/ssl/tls1.h index a11caf820a..dd1b4fb22d 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -281,6 +281,14 @@ extern "C" { #define TLSEXT_MAXLEN_host_name 255 +/* From RFC 5878 */ +#define TLSEXT_SUPPLEMENTALDATATYPE_authz_data 16386 +/* This is not IANA assigned. See + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#authorization-data-rules */ +#define TLSEXT_AUTHZDATAFORMAT_audit_proof 182 + +#define TLSEXT_MAXLEN_supplemental_data 1024*16 /* Let's limit to 16k */ + const char *SSL_get_servername(const SSL *s, const int type); int SSL_get_servername_type(const SSL *s); /* SSL_export_keying_material exports a value derived from the master secret, @@ -360,6 +368,13 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg) #define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) +/* Used by clients to process audit proofs. */ +#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb(ctx, cb) \ +SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB,(void (*)(void))cb) + +#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(ctx, arg) \ +SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG, 0, arg); + #ifndef OPENSSL_NO_HEARTBEATS #define SSL_TLSEXT_HB_ENABLED 0x01 #define SSL_TLSEXT_HB_DONT_SEND_REQUESTS 0x02 -- 2.34.1