diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2007-09-26 21:56:59 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2007-09-26 21:56:59 +0000 |
commit | 67c8e7f41486934b6809673b6d836d38eaf2383b (patch) | |
tree | 06fd94dda26946a4d53a63a98b280aeffbc0aac7 /ssl | |
parent | 74eb3e091412be483d419c6ae3cdb6be2c1fb273 (diff) | |
download | openssl-67c8e7f41486934b6809673b6d836d38eaf2383b.tar.gz |
Support for certificate status TLS extension.
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/s23_clnt.c | 2 | ||||
-rw-r--r-- | ssl/s3_clnt.c | 90 | ||||
-rw-r--r-- | ssl/s3_lib.c | 46 | ||||
-rw-r--r-- | ssl/s3_srvr.c | 56 | ||||
-rw-r--r-- | ssl/ssl.h | 29 | ||||
-rw-r--r-- | ssl/ssl3.h | 5 | ||||
-rw-r--r-- | ssl/ssl_err.c | 3 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 17 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 2 | ||||
-rw-r--r-- | ssl/t1_enc.c | 2 | ||||
-rw-r--r-- | ssl/t1_lib.c | 233 | ||||
-rw-r--r-- | ssl/tls1.h | 35 |
12 files changed, 514 insertions, 6 deletions
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index c500a932a7..78c39d9af5 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -283,6 +283,8 @@ static int ssl23_client_hello(SSL *s) if (s->tlsext_hostname != NULL) ssl2_compat = 0; + if (s->tlsext_status_type != -1) + ssl2_compat = 0; #ifdef TLSEXT_TYPE_opaque_prf_input if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL) diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index f8f43eb938..b7d8d4213b 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -307,10 +307,23 @@ int ssl3_connect(SSL *s) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state=SSL3_ST_CR_CERT_STATUS_A; + else + s->state=SSL3_ST_CR_KEY_EXCH_A; + } + else + { + skip = 1; + s->state=SSL3_ST_CR_KEY_EXCH_A; } +#else else skip=1; + s->state=SSL3_ST_CR_KEY_EXCH_A; +#endif s->init_num=0; break; @@ -473,6 +486,14 @@ int ssl3_connect(SSL *s) s->state=SSL3_ST_CR_FINISHED_A; s->init_num=0; break; + + case SSL3_ST_CR_CERT_STATUS_A: + case SSL3_ST_CR_CERT_STATUS_B: + ret=ssl3_get_cert_status(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_CR_KEY_EXCH_A; + s->init_num=0; + break; #endif case SSL3_ST_CR_FINISHED_A: @@ -1795,6 +1816,75 @@ f_err: err: return(-1); } + +int ssl3_get_cert_status(SSL *s) + { + int ok, al; + unsigned long resplen; + long n; + const unsigned char *p; + + n=s->method->ssl_get_message(s, + SSL3_ST_CR_CERT_STATUS_A, + SSL3_ST_CR_CERT_STATUS_B, + SSL3_MT_CERTIFICATE_STATUS, + 16384, + &ok); + + if (!ok) return((int)n); + if (n < 4) + { + /* need at least status type + length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + p = (unsigned char *)s->init_msg; + if (*p++ != TLSEXT_STATUSTYPE_ocsp) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE); + goto f_err; + } + n2l3(p, resplen); + if (resplen + 4 != n) + { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH); + goto f_err; + } + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = BUF_memdup(p, resplen); + if (!s->tlsext_ocsp_resp) + { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE); + goto f_err; + } + s->tlsext_ocsp_resplen = resplen; + if (s->ctx->tlsext_status_cb) + { + int ret; + ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (ret == 0) + { + al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE); + goto f_err; + } + if (ret < 0) + { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE); + goto f_err; + } + } + return 1; +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + return(-1); + } #endif int ssl3_get_server_done(SSL *s) diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 548eeef6f3..9910a132e8 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -2383,6 +2383,43 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) break; #endif + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: + s->tlsext_status_type=larg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS: + *(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts; + ret = 1; + break; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS: + s->tlsext_ocsp_exts = parg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS: + *(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids; + ret = 1; + break; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS: + s->tlsext_ocsp_ids = parg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: + *(unsigned char **)parg = s->tlsext_ocsp_resp; + return s->tlsext_ocsp_resplen; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = parg; + s->tlsext_ocsp_resplen = larg; + ret = 1; + break; + #endif /* !OPENSSL_NO_TLSEXT */ default: break; @@ -2610,6 +2647,11 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) return 1; #endif + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: + ctx->tlsext_status_arg=parg; + return 1; + break; + #endif /* !OPENSSL_NO_TLSEXT */ /* A Thawte special :-) */ @@ -2668,6 +2710,10 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) break; #endif + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: + ctx->tlsext_status_cb=(int (*)(SSL *,void *))fp; + break; + #endif default: return(0); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 697ab725bd..cc01cb109f 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -332,10 +332,23 @@ int ssl3_accept(SSL *s) { ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state=SSL3_ST_SW_CERT_STATUS_A; + else + s->state=SSL3_ST_SW_KEY_EXCH_A; } else + { + skip = 1; + s->state=SSL3_ST_SW_KEY_EXCH_A; + } +#else + else skip=1; + s->state=SSL3_ST_SW_KEY_EXCH_A; +#endif s->init_num=0; break; @@ -551,6 +564,14 @@ int ssl3_accept(SSL *s) s->init_num=0; break; + case SSL3_ST_SW_CERT_STATUS_A: + case SSL3_ST_SW_CERT_STATUS_B: + ret=ssl3_send_cert_status(s); + if (ret <= 0) goto end; + s->state=SSL3_ST_SW_KEY_EXCH_A; + s->init_num=0; + break; + #endif case SSL3_ST_SW_CHANGE_A: @@ -2823,4 +2844,39 @@ int ssl3_send_newsession_ticket(SSL *s) /* SSL3_ST_SW_SESSION_TICKET_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } + +int ssl3_send_cert_status(SSL *s) + { + if (s->state == SSL3_ST_SW_CERT_STATUS_A) + { + unsigned char *p; + /* Grow buffer if need be: the length calculation is as + * follows 1 (message type) + 3 (message length) + + * 1 (ocsp response type) + 3 (ocsp response length) + * + (ocsp response) + */ + if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) + return -1; + + p=(unsigned char *)s->init_buf->data; + + /* do the header */ + *(p++)=SSL3_MT_CERTIFICATE_STATUS; + /* message length */ + l2n3(s->tlsext_ocsp_resplen + 4, p); + /* status type */ + *(p++)= s->tlsext_status_type; + /* length of OCSP response */ + l2n3(s->tlsext_ocsp_resplen, p); + /* actual response */ + memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen); + /* number of bytes to write */ + s->init_num = 8 + s->tlsext_ocsp_resplen; + s->state=SSL3_ST_SW_CERT_STATUS_B; + s->init_off = 0; + } + + /* SSL3_ST_SW_CERT_STATUS_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } #endif @@ -800,6 +800,11 @@ struct ssl_ctx_st unsigned char tlsext_tick_hmac_key[16]; unsigned char tlsext_tick_aes_key[16]; + /* certificate status request info */ + /* Callback for status request */ + int (*tlsext_status_cb)(SSL *ssl, void *arg); + void *tlsext_status_arg; + /* draft-rescorla-tls-opaque-prf-input-00.txt information */ int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg); void *tlsext_opaque_prf_input_callback_arg; @@ -1083,6 +1088,18 @@ struct ssl_st 1 : prepare 2, allow last ack just after in server callback. 2 : don't call servername callback, no ack in server hello */ + /* certificate status request info */ + /* Status type or -1 if no status type */ + int tlsext_status_type; + /* Expect OCSP CertificateStatus message */ + int tlsext_status_expected; + /* OCSP status request only */ + STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids; + X509_EXTENSIONS *tlsext_ocsp_exts; + /* OCSP response received or to be sent */ + unsigned char *tlsext_ocsp_resp; + int tlsext_ocsp_resplen; + /* RFC4507 session ticket expected to be received or sent */ int tlsext_ticket_expected; #ifndef OPENSSL_NO_EC @@ -1317,6 +1334,15 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60 #define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61 #define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 #endif #define SSL_session_reused(ssl) \ @@ -1766,6 +1792,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL3_ENC 134 #define SSL_F_SSL3_GENERATE_KEY_BLOCK 238 #define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135 +#define SSL_F_SSL3_GET_CERT_STATUS 288 #define SSL_F_SSL3_GET_CERT_VERIFY 136 #define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137 #define SSL_F_SSL3_GET_CLIENT_HELLO 138 @@ -1964,6 +1991,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_INVALID_CHALLENGE_LENGTH 158 #define SSL_R_INVALID_COMMAND 280 #define SSL_R_INVALID_PURPOSE 278 +#define SSL_R_INVALID_STATUS_RESPONSE 328 #define SSL_R_INVALID_TICKET_KEYS_LENGTH 325 #define SSL_R_INVALID_TRUST 279 #define SSL_R_KEY_ARG_TOO_LONG 284 @@ -2132,6 +2160,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 #define SSL_R_UNSUPPORTED_PROTOCOL 258 #define SSL_R_UNSUPPORTED_SSL_VERSION 259 +#define SSL_R_UNSUPPORTED_STATUS_TYPE 329 #define SSL_R_WRITE_BIO_NOT_SET 260 #define SSL_R_WRONG_CIPHER_RETURNED 261 #define SSL_R_WRONG_MESSAGE_TYPE 262 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index e04226f46f..646a8e6cce 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -545,6 +545,8 @@ typedef struct ssl3_state_st #define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT) #define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT) #define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT) /* server */ /* extra state */ @@ -588,6 +590,8 @@ typedef struct ssl3_state_st #define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT) #define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT) #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_MT_HELLO_REQUEST 0 #define SSL3_MT_CLIENT_HELLO 1 @@ -600,6 +604,7 @@ typedef struct ssl3_state_st #define SSL3_MT_CERTIFICATE_VERIFY 15 #define SSL3_MT_CLIENT_KEY_EXCHANGE 16 #define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 #define DTLS1_MT_HELLO_VERIFY_REQUEST 3 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 3121e0e70c..d9c0e35681 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -140,6 +140,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL3_ENC), "SSL3_ENC"}, {ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"}, {ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), "SSL3_GET_CERTIFICATE_REQUEST"}, +{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "SSL3_GET_CERT_STATUS"}, {ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "SSL3_GET_CERT_VERIFY"}, {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE), "SSL3_GET_CLIENT_CERTIFICATE"}, {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "SSL3_GET_CLIENT_HELLO"}, @@ -341,6 +342,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"}, {ERR_REASON(SSL_R_INVALID_COMMAND) ,"invalid command"}, {ERR_REASON(SSL_R_INVALID_PURPOSE) ,"invalid purpose"}, +{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE),"invalid status response"}, {ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH),"invalid ticket keys length"}, {ERR_REASON(SSL_R_INVALID_TRUST) ,"invalid trust"}, {ERR_REASON(SSL_R_KEY_ARG_TOO_LONG) ,"key arg too long"}, @@ -509,6 +511,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"}, {ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL) ,"unsupported protocol"}, {ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION),"unsupported ssl version"}, +{ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE),"unsupported status type"}, {ERR_REASON(SSL_R_WRITE_BIO_NOT_SET) ,"write bio not set"}, {ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED) ,"wrong cipher returned"}, {ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE) ,"wrong message type"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 00a93eeee9..c5d9f0e93e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -152,6 +152,7 @@ #include <openssl/lhash.h> #include <openssl/x509v3.h> #include <openssl/rand.h> +#include <openssl/ocsp.h> #ifndef OPENSSL_NO_DH #include <openssl/dh.h> #endif @@ -340,6 +341,12 @@ SSL *SSL_new(SSL_CTX *ctx) s->tlsext_debug_cb = 0; s->tlsext_debug_arg = NULL; s->tlsext_ticket_expected = 0; + s->tlsext_status_type = -1; + s->tlsext_status_expected = 0; + s->tlsext_ocsp_ids = NULL; + s->tlsext_ocsp_exts = NULL; + s->tlsext_ocsp_resp = NULL; + s->tlsext_ocsp_resplen = -1; CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); s->initial_ctx=ctx; #endif @@ -543,6 +550,13 @@ void SSL_free(SSL *s) if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist); #endif /* OPENSSL_NO_EC */ if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input); + if (s->tlsext_ocsp_exts) + sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, + X509_EXTENSION_free); + if (s->tlsext_ocsp_ids) + sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); #endif if (s->client_CA != NULL) @@ -1556,6 +1570,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0)) ret->options |= SSL_OP_NO_TICKET; + ret->tlsext_status_cb = 0; + ret->tlsext_status_arg = NULL; + #endif #ifndef OPENSSL_NO_PSK ret->psk_identity_hint=NULL; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 50a8acc015..cb93ff2188 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -829,6 +829,7 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p); void ssl3_init_finished_mac(SSL *s); int ssl3_send_server_certificate(SSL *s); int ssl3_send_newsession_ticket(SSL *s); +int ssl3_send_cert_status(SSL *s); int ssl3_get_finished(SSL *s,int state_a,int state_b); int ssl3_setup_key_block(SSL *s); int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b); @@ -921,6 +922,7 @@ int ssl3_client_hello(SSL *s); int ssl3_get_server_hello(SSL *s); int ssl3_get_certificate_request(SSL *s); int ssl3_get_new_session_ticket(SSL *s); +int ssl3_get_cert_status(SSL *s); int ssl3_get_server_done(SSL *s); int ssl3_send_client_verify(SSL *s); int ssl3_send_client_certificate(SSL *s); diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 3509f62b18..4aa7600fe7 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -899,7 +899,7 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, { unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH]; const void *co = NULL, *so = NULL; - int col = 0, sol = NULL; + int col = 0, sol = 0; #ifdef KSSL_DEBUG printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 1aaf8905c8..476e4240e5 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -113,6 +113,7 @@ #include <openssl/objects.h> #include <openssl/evp.h> #include <openssl/hmac.h> +#include <openssl/ocsp.h> #include "ssl_locl.h" const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; @@ -387,6 +388,54 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { + int i; + long extlen, idlen, itmp; + OCSP_RESPID *id; + + idlen = 0; + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + itmp = i2d_OCSP_RESPID(id, NULL); + if (itmp <= 0) + return NULL; + idlen += itmp + 2; + } + + if (s->tlsext_ocsp_exts) + { + extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); + if (extlen < 0) + return NULL; + } + else + extlen = 0; + + if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request, ret); + if (extlen + idlen > 0xFFF0) + return NULL; + s2n(extlen + idlen + 5, ret); + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + s2n(idlen, ret); + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) + { + /* save position of id len */ + unsigned char *q = ret; + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + /* skip over id len */ + ret += 2; + itmp = i2d_OCSP_RESPID(id, &ret); + /* write id len */ + s2n(itmp, q); + } + s2n(extlen, ret); + if (extlen > 0) + i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); + } + if ((extdatalen = ret-p-2)== 0) return p; @@ -432,7 +481,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } /* Currently the server should not respond with a SupportedCurves extension */ #endif /* OPENSSL_NO_EC */ - + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { @@ -441,6 +490,13 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(0,ret); } + if (s->tlsext_status_expected) + { + if ((long)(limit - ret - 4) < 0) return NULL; + s2n(TLSEXT_TYPE_status_request,ret); + s2n(0,ret); + } + #ifdef TLSEXT_TYPE_opaque_prf_input if (s->s3->server_opaque_prf_input != NULL) { @@ -473,6 +529,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short len; unsigned char *data = *p; s->servername_done = 0; + s->tlsext_status_type = -1; if (data >= (d+n-2)) return 1; @@ -675,6 +732,106 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } #endif + else if (type == TLSEXT_TYPE_status_request + && s->ctx->tlsext_status_cb) + { + + if (size < 5) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + s->tlsext_status_type = *data++; + size--; + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + { + const unsigned char *sdata; + int dsize; + /* Read in responder_id_list */ + n2s(data,dsize); + size -= 2; + if (dsize > size ) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + while (dsize > 0) + { + OCSP_RESPID *id; + int idsize; + if (dsize < 4) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data, idsize); + dsize -= 2 + idsize; + if (dsize < 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + data += idsize; + id = d2i_OCSP_RESPID(NULL, + &sdata, idsize); + if (!id) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (data != sdata) + { + OCSP_RESPID_free(id); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!s->tlsext_ocsp_ids + && !(s->tlsext_ocsp_ids = + sk_OCSP_RESPID_new_null())) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!sk_OCSP_RESPID_push( + s->tlsext_ocsp_ids, id)) + { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + /* Read in request_extensions */ + n2s(data,dsize); + size -= 2; + if (dsize > size) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + if (dsize > 0) + { + s->tlsext_ocsp_exts = + d2i_X509_EXTENSIONS(NULL, + &sdata, dsize); + if (!s->tlsext_ocsp_exts + || (data + dsize != sdata)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } + /* We don't know what to do with any other type + * so ignore it. + */ + else + s->tlsext_status_type = -1; + } /* session ticket processed earlier */ data+=size; @@ -791,6 +948,19 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } #endif + else if (type == TLSEXT_TYPE_status_request) + { + /* MUST be empty and only sent if we've requested + * a status request message. + */ + if ((s->tlsext_status_type == -1) || (size > 0)) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* Set flag to expect CertificateStatus message */ + s->tlsext_status_expected = 1; + } data+=size; } @@ -822,6 +992,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } } + /* If we've requested certificate status and we wont get one + * tell the callback + */ + if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) + && s->ctx->tlsext_status_cb) + { + int r; + /* Set resp to NULL, resplen to -1 so callback knows + * there is no response. + */ + if (s->tlsext_ocsp_resp) + { + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + } + s->tlsext_ocsp_resplen = -1; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (r == 0) + { + *al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + return 0; + } + if (r < 0) + { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + *p = data; return 1; } @@ -966,6 +1165,36 @@ int ssl_check_clienthello_tlsext(SSL *s) else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); + /* If status request then ask callback what to do. + * Note: this must be called after servername callbacks in case + * the certificate has changed. + */ + if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb) + { + int r; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + switch (r) + { + /* We don't want to send a status request response */ + case SSL_TLSEXT_ERR_NOACK: + s->tlsext_status_expected = 0; + break; + /* status request response should be sent */ + case SSL_TLSEXT_ERR_OK: + if (s->tlsext_ocsp_resp) + s->tlsext_status_expected = 1; + else + s->tlsext_status_expected = 0; + break; + /* something bad happened */ + case SSL_TLSEXT_ERR_ALERT_FATAL: + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + else + s->tlsext_status_expected = 0; #ifdef TLSEXT_TYPE_opaque_prf_input { @@ -1022,8 +1251,8 @@ int ssl_check_clienthello_tlsext(SSL *s) al = SSL_AD_HANDSHAKE_FAILURE; } } -#endif +#endif err: switch (ret) { diff --git a/ssl/tls1.h b/ssl/tls1.h index cac8d0ea22..d831eecd87 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -203,6 +203,8 @@ extern "C" { /* NameType value from RFC 3546 */ #define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 /* ECPointFormat values from draft-ietf-tls-ecc-12 */ #define TLSEXT_ECPOINTFORMAT_first 0 @@ -227,12 +229,33 @@ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb) #define SSL_set_tlsext_debug_arg(ssl, arg) \ SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg) +#define SSL_set_tlsext_status_type(ssl, type) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL) + +#define SSL_get_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_set_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_get_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_set_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg) + +#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg) + #define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb) -#define SSL_TLSEXT_ERR_OK 0 -#define SSL_TLSEXT_ERR_ALERT_WARNING 1 -#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 #define SSL_TLSEXT_ERR_NOACK 3 #define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ @@ -243,6 +266,12 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg) #define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \ SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys)) +#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb) + +#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg) + #define SSL_set_tlsext_opaque_prf_input(s, src, len) \ SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src) #define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \ |