comparison src/event/ngx_event_openssl.c @ 6854:75e7d55214bd

SSL: support AES256 encryption of tickets. This implies ticket key size of 80 bytes instead of previously used 48, as both HMAC and AES keys are 32 bytes now. When an old 48-byte ticket key is provided, we fall back to using backward-compatible AES128 encryption. OpenSSL switched to using AES256 in 1.1.0, and we are providing equivalent security. While here, order of HMAC and AES keys was reverted to make the implementation compatible with keys used by OpenSSL with SSL_CTX_set_tlsext_ticket_keys(). Prodded by Christian Klinger.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 23 Dec 2016 17:28:20 +0300
parents 25d0d6dabe00
children 5cb85b0ee00b
comparison
equal deleted inserted replaced
6853:c85dfd99a2dd 6854:75e7d55214bd
2854 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 2854 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
2855 2855
2856 ngx_int_t 2856 ngx_int_t
2857 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) 2857 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
2858 { 2858 {
2859 u_char buf[48]; 2859 u_char buf[80];
2860 size_t size;
2860 ssize_t n; 2861 ssize_t n;
2861 ngx_str_t *path; 2862 ngx_str_t *path;
2862 ngx_file_t file; 2863 ngx_file_t file;
2863 ngx_uint_t i; 2864 ngx_uint_t i;
2864 ngx_array_t *keys; 2865 ngx_array_t *keys;
2897 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, 2898 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2898 ngx_fd_info_n " \"%V\" failed", &file.name); 2899 ngx_fd_info_n " \"%V\" failed", &file.name);
2899 goto failed; 2900 goto failed;
2900 } 2901 }
2901 2902
2902 if (ngx_file_size(&fi) != 48) { 2903 size = ngx_file_size(&fi);
2904
2905 if (size != 48 && size != 80) {
2903 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2906 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2904 "\"%V\" must be 48 bytes", &file.name); 2907 "\"%V\" must be 48 or 80 bytes", &file.name);
2905 goto failed; 2908 goto failed;
2906 } 2909 }
2907 2910
2908 n = ngx_read_file(&file, buf, 48, 0); 2911 n = ngx_read_file(&file, buf, size, 0);
2909 2912
2910 if (n == NGX_ERROR) { 2913 if (n == NGX_ERROR) {
2911 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, 2914 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2912 ngx_read_file_n " \"%V\" failed", &file.name); 2915 ngx_read_file_n " \"%V\" failed", &file.name);
2913 goto failed; 2916 goto failed;
2914 } 2917 }
2915 2918
2916 if (n != 48) { 2919 if ((size_t) n != size) {
2917 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, 2920 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
2918 ngx_read_file_n " \"%V\" returned only " 2921 ngx_read_file_n " \"%V\" returned only "
2919 "%z bytes instead of 48", &file.name, n); 2922 "%z bytes instead of %uz", &file.name, n, size);
2920 goto failed; 2923 goto failed;
2921 } 2924 }
2922 2925
2923 key = ngx_array_push(keys); 2926 key = ngx_array_push(keys);
2924 if (key == NULL) { 2927 if (key == NULL) {
2925 goto failed; 2928 goto failed;
2926 } 2929 }
2927 2930
2928 ngx_memcpy(key->name, buf, 16); 2931 if (size == 48) {
2929 ngx_memcpy(key->aes_key, buf + 16, 16); 2932 key->size = 48;
2930 ngx_memcpy(key->hmac_key, buf + 32, 16); 2933 ngx_memcpy(key->name, buf, 16);
2934 ngx_memcpy(key->aes_key, buf + 16, 16);
2935 ngx_memcpy(key->hmac_key, buf + 32, 16);
2936
2937 } else {
2938 key->size = 80;
2939 ngx_memcpy(key->name, buf, 16);
2940 ngx_memcpy(key->hmac_key, buf + 16, 32);
2941 ngx_memcpy(key->aes_key, buf + 48, 32);
2942 }
2931 2943
2932 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { 2944 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
2933 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, 2945 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
2934 ngx_close_file_n " \"%V\" failed", &file.name); 2946 ngx_close_file_n " \"%V\" failed", &file.name);
2935 } 2947 }
2970 static int 2982 static int
2971 ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, 2983 ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
2972 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, 2984 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
2973 HMAC_CTX *hctx, int enc) 2985 HMAC_CTX *hctx, int enc)
2974 { 2986 {
2987 size_t size;
2975 SSL_CTX *ssl_ctx; 2988 SSL_CTX *ssl_ctx;
2976 ngx_uint_t i; 2989 ngx_uint_t i;
2977 ngx_array_t *keys; 2990 ngx_array_t *keys;
2978 ngx_connection_t *c; 2991 ngx_connection_t *c;
2979 ngx_ssl_session_ticket_key_t *key; 2992 ngx_ssl_session_ticket_key_t *key;
2984 #endif 2997 #endif
2985 2998
2986 c = ngx_ssl_get_connection(ssl_conn); 2999 c = ngx_ssl_get_connection(ssl_conn);
2987 ssl_ctx = c->ssl->session_ctx; 3000 ssl_ctx = c->ssl->session_ctx;
2988 3001
2989 cipher = EVP_aes_128_cbc();
2990 #ifdef OPENSSL_NO_SHA256 3002 #ifdef OPENSSL_NO_SHA256
2991 digest = EVP_sha1(); 3003 digest = EVP_sha1();
2992 #else 3004 #else
2993 digest = EVP_sha256(); 3005 digest = EVP_sha256();
2994 #endif 3006 #endif
3006 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 3018 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
3007 "ssl session ticket encrypt, key: \"%*s\" (%s session)", 3019 "ssl session ticket encrypt, key: \"%*s\" (%s session)",
3008 ngx_hex_dump(buf, key[0].name, 16) - buf, buf, 3020 ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
3009 SSL_session_reused(ssl_conn) ? "reused" : "new"); 3021 SSL_session_reused(ssl_conn) ? "reused" : "new");
3010 3022
3023 if (key[0].size == 48) {
3024 cipher = EVP_aes_128_cbc();
3025 size = 16;
3026
3027 } else {
3028 cipher = EVP_aes_256_cbc();
3029 size = 32;
3030 }
3031
3011 if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) { 3032 if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
3012 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "RAND_bytes() failed"); 3033 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "RAND_bytes() failed");
3013 return -1; 3034 return -1;
3014 } 3035 }
3015 3036
3018 "EVP_EncryptInit_ex() failed"); 3039 "EVP_EncryptInit_ex() failed");
3019 return -1; 3040 return -1;
3020 } 3041 }
3021 3042
3022 #if OPENSSL_VERSION_NUMBER >= 0x10000000L 3043 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
3023 if (HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL) != 1) { 3044 if (HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL) != 1) {
3024 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed"); 3045 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
3025 return -1; 3046 return -1;
3026 } 3047 }
3027 #else 3048 #else
3028 HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL); 3049 HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL);
3029 #endif 3050 #endif
3030 3051
3031 ngx_memcpy(name, key[0].name, 16); 3052 ngx_memcpy(name, key[0].name, 16);
3032 3053
3033 return 1; 3054 return 1;
3052 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 3073 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
3053 "ssl session ticket decrypt, key: \"%*s\"%s", 3074 "ssl session ticket decrypt, key: \"%*s\"%s",
3054 ngx_hex_dump(buf, key[i].name, 16) - buf, buf, 3075 ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
3055 (i == 0) ? " (default)" : ""); 3076 (i == 0) ? " (default)" : "");
3056 3077
3078 if (key[i].size == 48) {
3079 cipher = EVP_aes_128_cbc();
3080 size = 16;
3081
3082 } else {
3083 cipher = EVP_aes_256_cbc();
3084 size = 32;
3085 }
3086
3057 #if OPENSSL_VERSION_NUMBER >= 0x10000000L 3087 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
3058 if (HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL) != 1) { 3088 if (HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL) != 1) {
3059 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed"); 3089 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
3060 return -1; 3090 return -1;
3061 } 3091 }
3062 #else 3092 #else
3063 HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL); 3093 HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL);
3064 #endif 3094 #endif
3065 3095
3066 if (EVP_DecryptInit_ex(ectx, cipher, NULL, key[i].aes_key, iv) != 1) { 3096 if (EVP_DecryptInit_ex(ectx, cipher, NULL, key[i].aes_key, iv) != 1) {
3067 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, 3097 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
3068 "EVP_DecryptInit_ex() failed"); 3098 "EVP_DecryptInit_ex() failed");