Rearrange and test authz extension.
authorBen Laurie <ben@openssl.org>
Thu, 7 Jun 2012 13:20:20 +0000 (13:20 +0000)
committerBen Laurie <ben@openssl.org>
Thu, 7 Jun 2012 13:20:20 +0000 (13:20 +0000)
apps/s_server.c
ssl/ssl.h
ssl/ssl_err.c
ssl/ssl_rsa.c
ssl/ssltest.c

index 261fe0883fcdb143c63fdf170723de7842b782ca..cfe9a34c37de633f00a466dcb5092a31ec96d024 100644 (file)
@@ -312,8 +312,6 @@ static int cert_chain = 0;
 #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
@@ -1488,33 +1486,6 @@ bad:
                        next_proto.data = NULL;
                        }
 # 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 */
                }
 
@@ -1811,7 +1782,7 @@ 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))
+       if (s_authz_file != NULL && !SSL_CTX_use_authz_file(ctx, s_authz_file))
                goto end;
 #endif
 #ifndef OPENSSL_NO_TLSEXT
@@ -1998,8 +1969,6 @@ 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
index 5f0dbe7a29ed71df9592b312439d81eb2333a75b..f5a5e7e43aeb02071a95c73ae1ee7c8a12e9657d 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1773,8 +1773,16 @@ 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
+/* Set authz data for the current active cert. */
 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);
+/* Get the authz of type 'type' associated with the current active cert. */
+const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
+                                           size_t *data_length);
+#ifndef OPENSSL_NO_STDIO
+int    SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file);
+int    SSL_use_authz_file(SSL *ssl, const char *file);
+#endif
 #endif
 
 #ifndef OPENSSL_NO_STDIO
@@ -2122,6 +2130,7 @@ void ERR_load_SSL_strings(void);
 /* Error codes for the SSL functions. */
 
 /* Function codes. */
+#define SSL_F_AUTHZ_FIND_DATA                           330
 #define SSL_F_AUTHZ_VALIDATE                            323
 #define SSL_F_CLIENT_CERTIFICATE                        100
 #define SSL_F_CLIENT_FINISHED                           167
@@ -2165,6 +2174,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_GET_SERVER_HELLO                          109
 #define SSL_F_GET_SERVER_VERIFY                                 110
 #define SSL_F_I2D_SSL_SESSION                           111
+#define SSL_F_READ_AUTHZ                                329
 #define SSL_F_READ_N                                    112
 #define SSL_F_REQUEST_CERTIFICATE                       113
 #define SSL_F_SERVER_FINISH                             239
index 8e3594007b6e975f8c4094dbf9bfdf7c5cc1bd71..1470cee234d65294e5951384a45051bbefa905a2 100644 (file)
@@ -70,6 +70,7 @@
 
 static ERR_STRING_DATA SSL_str_functs[]=
        {
+{ERR_FUNC(SSL_F_AUTHZ_FIND_DATA),      "AUTHZ_FIND_DATA"},
 {ERR_FUNC(SSL_F_AUTHZ_VALIDATE),       "AUTHZ_VALIDATE"},
 {ERR_FUNC(SSL_F_CLIENT_CERTIFICATE),   "CLIENT_CERTIFICATE"},
 {ERR_FUNC(SSL_F_CLIENT_FINISHED),      "CLIENT_FINISHED"},
@@ -113,6 +114,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_GET_SERVER_HELLO),     "GET_SERVER_HELLO"},
 {ERR_FUNC(SSL_F_GET_SERVER_VERIFY),    "GET_SERVER_VERIFY"},
 {ERR_FUNC(SSL_F_I2D_SSL_SESSION),      "i2d_SSL_SESSION"},
+{ERR_FUNC(SSL_F_READ_AUTHZ),   "READ_AUTHZ"},
 {ERR_FUNC(SSL_F_READ_N),       "READ_N"},
 {ERR_FUNC(SSL_F_REQUEST_CERTIFICATE),  "REQUEST_CERTIFICATE"},
 {ERR_FUNC(SSL_F_SERVER_FINISH),        "SERVER_FINISH"},
index 855952d54cfb72454e3770f2d883d7b344a0a2b8..1babdef3c645e7d1eaa327ad6efb68cb4b27dc14 100644 (file)
@@ -855,6 +855,46 @@ static char authz_validate(const unsigned char *authz, size_t length)
                }
        }
 
+static const unsigned char *authz_find_data(const unsigned char *authz,
+                                           size_t authz_length,
+                                           unsigned char data_type,
+                                           size_t *data_length)
+       {
+       if (authz == NULL) return NULL;
+       if (!authz_validate(authz, authz_length))
+               {
+               SSLerr(SSL_F_AUTHZ_FIND_DATA,SSL_R_INVALID_AUTHZ_DATA);
+               return NULL;
+               }
+
+       for (;;)
+               {
+               unsigned char type;
+               unsigned short len;
+               if (!authz_length)
+                       return NULL;
+
+               type = *(authz++);
+               authz_length--;
+
+               /* We've validated the authz data, so we don't have to
+                * check again that we have enough bytes left. */
+               len = ((unsigned short) authz[0]) << 8 |
+                     ((unsigned short) authz[1]);
+               authz += 2;
+               authz_length -= 2;
+               if (type == data_type)
+                       {
+                       *data_length = len;
+                       return authz;
+                       }
+               authz += len;
+               authz_length -= len;
+               }
+       /* No match */
+       return NULL;
+       }
+
 static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length)
        {
        CERT_PKEY *current_key = c->key;
@@ -901,4 +941,90 @@ int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length)
                }
        return ssl_set_authz(ssl->cert, authz, authz_length);
        }
+
+const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
+                                           size_t *data_length)
+       {
+       CERT_PKEY *current_key;
+
+       if (ctx->cert == NULL)
+               return NULL;
+       current_key = ctx->cert->key;
+       if (current_key->authz == NULL)
+               return NULL;
+       return authz_find_data(current_key->authz,
+               current_key->authz_length, type, data_length);
+       }
+
+#ifndef OPENSSL_NO_STDIO
+/* read_authz returns a newly allocated buffer with authz data */
+static unsigned char *read_authz(const char *file, size_t *authz_length)
+       {
+       BIO *authz_in = NULL;
+       unsigned char *authz = NULL;
+       /* Allow authzs up to 64KB. */
+       static const size_t authz_limit = 65536;
+       size_t read_length;
+       unsigned char *ret = NULL;
+
+       authz_in = BIO_new(BIO_s_file_internal());
+       if (authz_in == NULL)
+               {
+               SSLerr(SSL_F_READ_AUTHZ,ERR_R_BUF_LIB);
+               goto end;
+               }
+
+       if (BIO_read_filename(authz_in,file) <= 0)
+               {
+               SSLerr(SSL_F_READ_AUTHZ,ERR_R_SYS_LIB);
+               goto end;
+               }
+
+       authz = OPENSSL_malloc(authz_limit);
+       read_length = BIO_read(authz_in, authz, authz_limit);
+       if (read_length == authz_limit || read_length <= 0)
+               {
+               SSLerr(SSL_F_READ_AUTHZ,SSL_R_AUTHZ_DATA_TOO_LARGE);
+               OPENSSL_free(authz);
+               goto end;
+               }
+       *authz_length = read_length;
+       ret = authz;
+end:
+       if (authz_in != NULL) BIO_free(authz_in);
+       return ret;
+       }
+
+int SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file)
+       {
+       unsigned char *authz = NULL;
+       size_t authz_length = 0;
+       int ret;
+
+       authz = read_authz(file, &authz_length);
+       if (authz == NULL)
+               return 0;
+
+       ret = SSL_CTX_use_authz(ctx, authz, authz_length);
+       /* SSL_CTX_use_authz makes a local copy of the authz. */
+       OPENSSL_free(authz);
+       return ret;
+       }
+
+int SSL_use_authz_file(SSL *ssl, const char *file)
+       {
+       unsigned char *authz = NULL;
+       size_t authz_length = 0;
+       int ret;
+
+       authz = read_authz(file, &authz_length);
+       if (authz == NULL)
+               return 0;
+
+       ret = SSL_use_authz(ssl, authz, authz_length);
+       /* SSL_use_authz makes a local copy of the authz. */
+       OPENSSL_free(authz);
+       return ret;
+       }
+#endif /* OPENSSL_NO_STDIO */
 #endif /* OPENSSL_NO_TLSEXT */
index 316bbb0c9582fe962945bd532c93eb3fd93c1d81..1f557dd9a1a31ceafe04dc077ad4371acb23d4ef 100644 (file)
@@ -369,6 +369,11 @@ static void sv_usage(void)
                       "                 (default is sect163r2).\n");
 #endif
        fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+#ifndef OPENSSL_NO_TLSEXT
+       fprintf(stderr," -server_authz arg - binary authz file for certificate\n");
+       fprintf(stderr," -c_support_proof  - indicate client support for server_authz audit proofs\n");
+       fprintf(stderr," -c_require_proof  - fail if no audit proof is sent\n");
+#endif
        }
 
 static void print_details(SSL *c_ssl, const char *prefix)
@@ -498,6 +503,56 @@ int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
        }
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+struct audit_proof_cb_arg_st
+       {
+       unsigned char *expected_proof;
+       size_t expected_proof_length;
+       int require;
+       };
+
+struct audit_proof_cb_arg_st c_expected = { NULL, 0, 0 };
+
+static int audit_proof_cb(SSL *s, void *arg)
+       {
+       const unsigned char *proof;
+       size_t proof_len;
+       SSL_SESSION *sess = SSL_get_session(s);
+       struct audit_proof_cb_arg_st *cb_arg = (struct audit_proof_cb_arg_st*)arg;
+
+       proof = SSL_SESSION_get_tlsext_authz_server_audit_proof(sess,
+               &proof_len);
+       if (proof != NULL)
+               {
+               if (proof_len == cb_arg->expected_proof_length &&
+                       cb_arg->expected_proof != NULL &&
+                       memcmp(proof, cb_arg->expected_proof, proof_len) == 0)
+                       {
+                       BIO_printf(bio_stdout, "Audit proof OK (%lu bytes).\n",
+                                  (long)proof_len);
+                       return 1;
+                       }
+               else
+                       {
+                       BIO_printf(bio_stdout, "Audit proof mismatch.\n");
+                       /* Cause handshake failure. */
+                       return 0;
+                       }
+               }
+
+       else /* proof == NULL */
+               {
+               BIO_printf(bio_stdout, "No audit proof found.\n");
+               if (cb_arg->require)
+                       {
+                       /* Cause handshake failure. */
+                       return 0;
+                       }
+               return 1;
+               }
+       }
+#endif
+
 int main(int argc, char *argv[])
        {
        char *CApath=NULL,*CAfile=NULL;
@@ -549,6 +604,11 @@ int main(int argc, char *argv[])
 #ifdef OPENSSL_FIPS
        int fips_mode=0;
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+       char *s_authz_file = NULL;
+       int c_support_proof = 0;
+       int c_require_proof = 0;
+#endif
 
        verbose = 0;
        debug = 0;
@@ -765,6 +825,24 @@ int main(int argc, char *argv[])
                        {
                        test_cipherlist = 1;
                        }
+#ifndef OPENSSL_NO_TLSEXT
+               else if(strcmp(*argv,"-server_authz") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       s_authz_file = *(++argv);
+                       tls1 = 1;
+                       }
+               else if (strcmp(*argv,"-c_support_proof") == 0)
+                       {
+                       c_support_proof = 1;
+                       tls1 = 1;
+                       }
+               else if (strcmp(*argv,"-c_require_proof") == 0)
+                       {
+                       c_require_proof = 1;
+                       tls1 = 1;
+                       }
+#endif
                else
                        {
                        fprintf(stderr,"unknown option %s\n",*argv);
@@ -798,6 +876,15 @@ bad:
                        "to avoid protocol mismatch.\n");
                EXIT(1);
                }
+       if (c_require_proof && s_authz_file == NULL && !force)
+               {
+               fprintf(stderr, "This case cannot work. -c_require_proof "
+                       "requires an audit proof, but none was supplied. "
+                       "Use -f to perform the test anyway (and\n-d to see "
+                       "what happens), or use -server_authz to supply an "
+                       "audit proof.\n");
+               EXIT(1);
+               }
 
 #ifdef OPENSSL_FIPS
        if(fips_mode)
@@ -1063,6 +1150,34 @@ bad:
                SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb);
                }
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+       if (s_authz_file != NULL)
+               {
+               if(!SSL_CTX_use_authz_file(s_ctx, s_authz_file))
+                       {
+                       BIO_printf(bio_err, "Unable to set authz data\n");
+                       goto end;
+                       }
+               }
+       if (c_support_proof || c_require_proof)
+               {
+               size_t proof_length;
+               const unsigned char *proof = SSL_CTX_get_authz_data(s_ctx,
+                       TLSEXT_AUTHZDATAFORMAT_audit_proof, &proof_length);
+               if (proof != NULL)
+                       {
+                       /* Store a local copy. */
+                       c_expected.expected_proof = OPENSSL_malloc(proof_length);
+                       c_expected.expected_proof_length = proof_length;
+                       memcpy(c_expected.expected_proof, proof, proof_length);
+                       }
+               c_expected.require = c_require_proof;
+               SSL_CTX_set_tlsext_authz_server_audit_proof_cb(c_ctx,
+                       audit_proof_cb);
+               SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(c_ctx,
+                       &c_expected);
+               }
+#endif
 
        c_ssl=SSL_new(c_ctx);
        s_ssl=SSL_new(s_ctx);
@@ -1137,6 +1252,10 @@ end:
 #endif
 #ifndef OPENSSL_NO_ENGINE
        ENGINE_cleanup();
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+       if (c_expected.expected_proof != NULL)
+               OPENSSL_free(c_expected.expected_proof);
 #endif
        CRYPTO_cleanup_all_ex_data();
        ERR_free_strings();