Give more information in the SSL_stateless return code
[openssl.git] / ssl / statem / extensions_srvr.c
index 60fa34201cb48bee1f678e3042732c27b24df528..b9692f46e4852550111cb952b15da636a970d348 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 
 /*
  * Message header + 2 bytes for protocol version + number of random bytes +
- * + number of bytes in legacy session id + 2 bytes for ciphersuite
- * + 1 byte for legacy compression + 2 bytes for extension block length
- * + 6 bytes for key_share extension + 4 bytes for cookie extension header
- * + the number of bytes in the cookie
+ * + 1 byte for legacy session id length + number of bytes in legacy session id
+ * + 2 bytes for ciphersuite + 1 byte for legacy compression
+ * + 2 bytes for extension block length + 6 bytes for key_share extension
+ * + 4 bytes for cookie extension header + the number of bytes in the cookie
  */
-#define MAX_HRR_SIZE    (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE \
+#define MAX_HRR_SIZE    (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE + 1 \
                          + SSL_MAX_SSL_SESSION_ID_LENGTH + 2 + 1 + 2 + 6 + 4 \
                          + MAX_COOKIE_SIZE)
 
@@ -276,6 +276,27 @@ int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
     return 1;
 }
 
+int tls_parse_ctos_sig_algs_cert(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx)
+{
+    PACKET supported_sig_algs;
+
+    if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs)
+            || PACKET_remaining(&supported_sig_algs) == 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS_CERT, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 1)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR,
+                 SSL_F_TLS_PARSE_CTOS_SIG_ALGS_CERT, SSL_R_BAD_EXTENSION);
+        return 0;
+    }
+
+    return 1;
+}
+
 int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
                             size_t chainidx)
 {
@@ -288,7 +309,7 @@ int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         return 0;
     }
 
-    if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs)) {
+    if (!s->hit && !tls1_save_sigalgs(s, &supported_sig_algs, 0)) {
         SSLfatal(s, SSL_AD_DECODE_ERROR,
                  SSL_F_TLS_PARSE_CTOS_SIG_ALGS, SSL_R_BAD_EXTENSION);
         return 0;
@@ -742,11 +763,10 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         return 0;
     }
 
-    hmaclen = sizeof(s->session_ctx->ext.cookie_hmac_key);
+    hmaclen = SHA256_DIGEST_LENGTH;
     if (EVP_DigestSignInit(hctx, NULL, EVP_sha256(), NULL, pkey) <= 0
-            || EVP_DigestSignUpdate(hctx, data,
-                                    rawlen - SHA256_DIGEST_LENGTH) <= 0
-            || EVP_DigestSignFinal(hctx, hmac, &hmaclen) <= 0
+            || EVP_DigestSign(hctx, hmac, &hmaclen, data,
+                              rawlen - SHA256_DIGEST_LENGTH) <= 0
             || hmaclen != SHA256_DIGEST_LENGTH) {
         EVP_MD_CTX_free(hctx);
         EVP_PKEY_free(pkey);
@@ -1008,6 +1028,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
     for (id = 0; PACKET_remaining(&identities) != 0; id++) {
         PACKET identity;
         unsigned long ticket_agel;
+        size_t idlen;
 
         if (!PACKET_get_length_prefixed_2(&identities, &identity)
                 || !PACKET_get_net_4(&identities, &ticket_agel)) {
@@ -1016,15 +1037,66 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             return 0;
         }
 
+        idlen = PACKET_remaining(&identity);
         if (s->psk_find_session_cb != NULL
-                && !s->psk_find_session_cb(s, PACKET_data(&identity),
-                                           PACKET_remaining(&identity),
+                && !s->psk_find_session_cb(s, PACKET_data(&identity), idlen,
                                            &sess)) {
             SSLfatal(s, SSL_AD_INTERNAL_ERROR,
                      SSL_F_TLS_PARSE_CTOS_PSK, SSL_R_BAD_EXTENSION);
             return 0;
         }
 
+        if(sess == NULL
+                && s->psk_server_callback != NULL
+                && idlen <= PSK_MAX_IDENTITY_LEN) {
+            char *pskid = NULL;
+            unsigned char pskdata[PSK_MAX_PSK_LEN];
+            unsigned int pskdatalen;
+
+            if (!PACKET_strndup(&identity, &pskid)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            pskdatalen = s->psk_server_callback(s, pskid, pskdata,
+                                                sizeof(pskdata));
+            OPENSSL_free(pskid);
+            if (pskdatalen > PSK_MAX_PSK_LEN) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            } else if (pskdatalen > 0) {
+                const SSL_CIPHER *cipher;
+                const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
+
+                /*
+                 * We found a PSK using an old style callback. We don't know
+                 * the digest so we default to SHA256 as per the TLSv1.3 spec
+                 */
+                cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
+                if (cipher == NULL) {
+                    OPENSSL_cleanse(pskdata, pskdatalen);
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                             ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+
+                sess = SSL_SESSION_new();
+                if (sess == NULL
+                        || !SSL_SESSION_set1_master_key(sess, pskdata,
+                                                        pskdatalen)
+                        || !SSL_SESSION_set_cipher(sess, cipher)
+                        || !SSL_SESSION_set_protocol_version(sess,
+                                                             TLS1_3_VERSION)) {
+                    OPENSSL_cleanse(pskdata, pskdatalen);
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_PSK,
+                             ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                OPENSSL_cleanse(pskdata, pskdatalen);
+            }
+        }
+
         if (sess != NULL) {
             /* We found a PSK */
             SSL_SESSION *sesstmp = ssl_session_dup(sess, 0);
@@ -1141,6 +1213,20 @@ err:
     return 0;
 }
 
+int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context,
+                                       X509 *x, size_t chainidx)
+{
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH,
+                 SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR);
+        return 0;
+    }
+
+    s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
+
+    return 1;
+}
+
 /*
  * Add the server's renegotiation binding
  */
@@ -1596,10 +1682,15 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
     EVP_PKEY *pkey;
     int ret = EXT_RETURN_FAIL;
 
-    if (s->ctx->app_gen_cookie_cb == NULL
-            || (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
+    if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
         return EXT_RETURN_NOT_SENT;
 
+    if (s->ctx->app_gen_cookie_cb == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
+                 SSL_R_NO_COOKIE_CALLBACK_SET);
+        return EXT_RETURN_FAIL;
+    }
+
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie)
             || !WPACKET_start_sub_packet_u16(pkt)
             || !WPACKET_start_sub_packet_u16(pkt)