RFC 5878 support.
authorBen Laurie <ben@openssl.org>
Wed, 30 May 2012 10:10:58 +0000 (10:10 +0000)
committerBen Laurie <ben@openssl.org>
Wed, 30 May 2012 10:10:58 +0000 (10:10 +0000)
19 files changed:
CHANGES
apps/s_apps.h
apps/s_cb.c
apps/s_client.c
apps/s_server.c
ssl/s23_clnt.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_cert.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssl_rsa.c
ssl/ssl_sess.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 7cca7f0..ec92910 100644 (file)
--- 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:
index 5de6532..4effcd2 100644 (file)
@@ -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
index b21a428..c07066b 100644 (file)
@@ -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");
index 16f1ac3..8cbb46e 100644 (file)
@@ -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
index bb791e0..762757b 100644 (file)
@@ -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)
                {
index 47673e7..807dd0b 100644 (file)
@@ -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
 
index cd4f0ad..e8fe968 100644 (file)
@@ -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
index 0456230..9653de6 100644 (file)
@@ -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:
                {
index 632b924..ba32484 100644 (file)
@@ -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
index 352e91b..31eccf9 100644 (file)
--- 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
index 4e72c17..84198ff 100644 (file)
@@ -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
-
index 222f703..fcf462d 100644 (file)
@@ -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)
index 0a43d24..ce00455 100644 (file)
@@ -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"},
index 679894c..cb098b3 100644 (file)
@@ -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;
index b83b174..d0167e8 100644 (file)
@@ -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);
index b7c1905..855952d 100644 (file)
 
 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 */
index 9e8f2e4..093ea60 100644 (file)
@@ -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;
index f62a004..12230e8 100644 (file)
@@ -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)
index a11caf8..dd1b4fb 100644 (file)
@@ -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