From: tedu Date: Wed, 16 Apr 2014 20:39:09 +0000 (+0000) Subject: add back SRP. i was being too greedy. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=f6b1586d31f749c2562d0274e25099bb35fc2537;p=openbsd add back SRP. i was being too greedy. --- diff --git a/lib/libssl/s3_clnt.c b/lib/libssl/s3_clnt.c index 1589cdc21e4..88be294ab78 100644 --- a/lib/libssl/s3_clnt.c +++ b/lib/libssl/s3_clnt.c @@ -365,6 +365,15 @@ ssl3_connect(SSL *s) ret = ssl3_get_server_done(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_SRP + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { + if ((ret = SRP_Calc_A_param(s)) <= 0) { + SSLerr(SSL_F_SSL3_CONNECT, SSL_R_SRP_A_CALC); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto end; + } + } +#endif if (s->s3->tmp.cert_req) s->state = SSL3_ST_CW_CERT_A; else @@ -1290,6 +1299,76 @@ ssl3_get_key_exchange(SSL *s) n -= param_len; } else #endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + n2s(p, i); + param_len = i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_N_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.N = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + n2s(p, i); + param_len += i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_G_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.g = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + i = (unsigned int)(p[0]); + p++; + param_len += i + 1; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_S_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.s = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + n2s(p, i); + param_len += i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_B_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.B = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + n -= param_len; + +/* We must check if there is a certificate */ +#ifndef OPENSSL_NO_RSA + if (alg_a & SSL_aRSA) + pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +#else + if (0) +; +#endif +#ifndef OPENSSL_NO_DSA + else if (alg_a & SSL_aDSS) + pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); +#endif + } else +#endif /* !OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_RSA if (alg_k & SSL_kRSA) { if ((rsa = RSA_new()) == NULL) { @@ -2492,6 +2571,33 @@ ssl3_send_client_key_exchange(SSL *s) EVP_PKEY_free(pub_key); } +#ifndef OPENSSL_NO_SRP + else if (alg_k & SSL_kSRP) { + if (s->srp_ctx.A != NULL) { + /* send off the data */ + n = BN_num_bytes(s->srp_ctx.A); + s2n(n, p); + BN_bn2bin(s->srp_ctx.A, p); + n += 2; + } else { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = SRP_generate_client_master_secret(s, s->session->master_key)) < 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif #ifndef OPENSSL_NO_PSK else if (alg_k & SSL_kPSK) { char identity[PSK_MAX_IDENTITY_LEN]; diff --git a/lib/libssl/s3_lib.c b/lib/libssl/s3_lib.c index f56dbe26d7c..68a4b8ca2de 100644 --- a/lib/libssl/s3_lib.c +++ b/lib/libssl/s3_lib.c @@ -2419,6 +2419,151 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[] = { }, #endif /* OPENSSL_NO_ECDH */ +#ifndef OPENSSL_NO_SRP + /* Cipher C01A */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01B */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01C */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01D */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01E */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01F */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C020 */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, + + /* Cipher C021 */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, + + /* Cipher C022 */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_ECDH /* HMAC based TLS v1.2 ciphersuites from RFC5289 */ @@ -2808,6 +2953,9 @@ ssl3_new(SSL *s) s->s3 = s3; +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_init(s); +#endif s->method->ssl_clear(s); return (1); err: @@ -2850,6 +2998,9 @@ ssl3_free(SSL *s) } if (s->s3->handshake_dgst) ssl3_free_digest_list(s); +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_free(s); +#endif OPENSSL_cleanse(s->s3, sizeof *s->s3); OPENSSL_free(s->s3); s->s3 = NULL; @@ -2934,6 +3085,13 @@ ssl3_clear(SSL *s) #endif } +#ifndef OPENSSL_NO_SRP +static char * +srp_password_from_info_cb(SSL *s, void *arg) +{ + return BUF_strdup(s->srp_ctx.info); +} +#endif long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) @@ -3375,6 +3533,36 @@ ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) return 1; break; +#ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + if (ctx->srp_ctx.login != NULL) + OPENSSL_free(ctx->srp_ctx.login); + ctx->srp_ctx.login = NULL; + if (parg == NULL) + break; + if (strlen((const char *)parg) > 255 || strlen((const char *)parg) < 1) { + SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_SRP_USERNAME); + return 0; + } + if ((ctx->srp_ctx.login = BUF_strdup((char *)parg)) == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_INTERNAL_ERROR); + return 0; + } + break; + case SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD: + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = srp_password_from_info_cb; + ctx->srp_ctx.info = parg; + break; + case SSL_CTRL_SET_SRP_ARG: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_cb_arg = parg; + break; + + case SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH: + ctx->srp_ctx.strength = larg; + break; +#endif #endif /* !OPENSSL_NO_TLSEXT */ /* A Thawte special :-) */ @@ -3452,6 +3640,23 @@ ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int))fp; break; +#ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_SRP_VERIFY_PARAM_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_verify_param_callback = + (int (*)(SSL *, void *))fp; + break; + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.TLS_ext_srp_username_callback = + (int (*)(SSL *, int *, void *))fp; + break; + case SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = + (char *(*)(SSL *, void *))fp; + break; +#endif #endif default: return (0); @@ -3557,6 +3762,10 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, mask_a = cert->mask_a; emask_k = cert->export_mask_k; emask_a = cert->export_mask_a; +#ifndef OPENSSL_NO_SRP + mask_k = cert->mask_k | s->srp_ctx.srp_Mask; + emask_k = cert->export_mask_k | s->srp_ctx.srp_Mask; +#endif #ifdef KSSL_DEBUG /* printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/ diff --git a/lib/libssl/s3_srvr.c b/lib/libssl/s3_srvr.c index 1a924f828e5..cc46e241d4f 100644 --- a/lib/libssl/s3_srvr.c +++ b/lib/libssl/s3_srvr.c @@ -180,6 +180,28 @@ static const SSL_METHOD return (NULL); } +#ifndef OPENSSL_NO_SRP +static int +ssl_check_srp_ext_ClientHello(SSL *s, int *al) +{ + int ret = SSL_ERROR_NONE; + + *al = SSL_AD_UNRECOGNIZED_NAME; + + if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) && + (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) { + if (s->srp_ctx.login == NULL) { + /* RFC 5054 says SHOULD reject, + we do so if There is no srp login name */ + ret = SSL3_AL_FATAL; + *al = SSL_AD_UNKNOWN_PSK_IDENTITY; + } else { + ret = SSL_srp_server_param_with_username(s, al); + } + } + return ret; +} +#endif IMPLEMENT_ssl3_meth_func(SSLv3_server_method, ssl3_accept, ssl_undefined_function, ssl3_get_server_method) @@ -317,6 +339,39 @@ ssl3_accept(SSL *s) if (ret <= 0) goto end; } +#ifndef OPENSSL_NO_SRP + { + int al; + if ((ret = + ssl_check_srp_ext_ClientHello(s, &al)) + < 0) { + /* + * Callback indicates further work to + * be done. + */ + s->rwstate = SSL_X509_LOOKUP; + goto end; + } + if (ret != SSL_ERROR_NONE) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + + /* + * This is not really an error but the + * only means for a client to detect + * whether srp is supported. + */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_SSL3_ACCEPT, + SSL_R_CLIENTHELLO_TLSEXT); + + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + + ret = -1; + goto end; + + } + } +#endif s->renegotiate = 2; s->state = SSL3_ST_SW_SRVR_HELLO_A; @@ -414,6 +469,10 @@ ssl3_accept(SSL *s) * hint if provided */ #ifndef OPENSSL_NO_PSK || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) +#endif +#ifndef OPENSSL_NO_SRP + /* SRP: send ServerKeyExchange */ + || (alg_k & SSL_kSRP) #endif || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH)) || (alg_k & SSL_kEECDH) @@ -1751,6 +1810,19 @@ ssl3_send_server_key_exchange(SSL *s) n += 2 + pskhintlen; } else #endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (type & SSL_kSRP) { + if ((s->srp_ctx.N == NULL) || (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, SSL_R_MISSING_SRP_PARAM); + goto err; + } + r[0] = s->srp_ctx.N; + r[1] = s->srp_ctx.g; + r[2] = s->srp_ctx.s; + r[3] = s->srp_ctx.B; + } else +#endif { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); @@ -1758,6 +1830,11 @@ ssl3_send_server_key_exchange(SSL *s) } for (i = 0; i < 4 && r[i] != NULL; i++) { nr[i] = BN_num_bytes(r[i]); +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) + n += 1 + nr[i]; + else +#endif n += 2 + nr[i]; } @@ -1783,6 +1860,12 @@ ssl3_send_server_key_exchange(SSL *s) p = &(d[4]); for (i = 0; i < 4 && r[i] != NULL; i++) { +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) { + *p = nr[i]; + p++; + } else +#endif s2n(nr[i], p); BN_bn2bin(r[i], p); p += nr[i]; @@ -2651,6 +2734,43 @@ ssl3_get_client_key_exchange(SSL *s) goto f_err; } else #endif +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + int param_len; + + n2s(p, i); + param_len = i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_SRP_A_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.A = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_BN_LIB); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = + SRP_generate_server_master_secret(s, + s->session->master_key)) < 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + p += i; + } else +#endif /* OPENSSL_NO_SRP */ if (alg_k & SSL_kGOST) { int ret = 0; EVP_PKEY_CTX *pkey_ctx; @@ -2731,7 +2851,9 @@ ssl3_get_client_key_exchange(SSL *s) return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) || defined(OPENSSL_NO_SRP) err: +#endif #ifndef OPENSSL_NO_ECDH EVP_PKEY_free(clnt_pub_pkey); EC_POINT_free(clnt_ecpoint); diff --git a/lib/libssl/src/ssl/s3_clnt.c b/lib/libssl/src/ssl/s3_clnt.c index 1589cdc21e4..88be294ab78 100644 --- a/lib/libssl/src/ssl/s3_clnt.c +++ b/lib/libssl/src/ssl/s3_clnt.c @@ -365,6 +365,15 @@ ssl3_connect(SSL *s) ret = ssl3_get_server_done(s); if (ret <= 0) goto end; +#ifndef OPENSSL_NO_SRP + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { + if ((ret = SRP_Calc_A_param(s)) <= 0) { + SSLerr(SSL_F_SSL3_CONNECT, SSL_R_SRP_A_CALC); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto end; + } + } +#endif if (s->s3->tmp.cert_req) s->state = SSL3_ST_CW_CERT_A; else @@ -1290,6 +1299,76 @@ ssl3_get_key_exchange(SSL *s) n -= param_len; } else #endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + n2s(p, i); + param_len = i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_N_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.N = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + n2s(p, i); + param_len += i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_G_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.g = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + i = (unsigned int)(p[0]); + p++; + param_len += i + 1; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_S_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.s = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + n2s(p, i); + param_len += i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_B_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.B = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + n -= param_len; + +/* We must check if there is a certificate */ +#ifndef OPENSSL_NO_RSA + if (alg_a & SSL_aRSA) + pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +#else + if (0) +; +#endif +#ifndef OPENSSL_NO_DSA + else if (alg_a & SSL_aDSS) + pkey = X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); +#endif + } else +#endif /* !OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_RSA if (alg_k & SSL_kRSA) { if ((rsa = RSA_new()) == NULL) { @@ -2492,6 +2571,33 @@ ssl3_send_client_key_exchange(SSL *s) EVP_PKEY_free(pub_key); } +#ifndef OPENSSL_NO_SRP + else if (alg_k & SSL_kSRP) { + if (s->srp_ctx.A != NULL) { + /* send off the data */ + n = BN_num_bytes(s->srp_ctx.A); + s2n(n, p); + BN_bn2bin(s->srp_ctx.A, p); + n += 2; + } else { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = SRP_generate_client_master_secret(s, s->session->master_key)) < 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif #ifndef OPENSSL_NO_PSK else if (alg_k & SSL_kPSK) { char identity[PSK_MAX_IDENTITY_LEN]; diff --git a/lib/libssl/src/ssl/s3_lib.c b/lib/libssl/src/ssl/s3_lib.c index f56dbe26d7c..68a4b8ca2de 100644 --- a/lib/libssl/src/ssl/s3_lib.c +++ b/lib/libssl/src/ssl/s3_lib.c @@ -2419,6 +2419,151 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[] = { }, #endif /* OPENSSL_NO_ECDH */ +#ifndef OPENSSL_NO_SRP + /* Cipher C01A */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01B */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01C */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 168, + }, + + /* Cipher C01D */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01E */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01F */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + + /* Cipher C020 */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aNULL, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, + + /* Cipher C021 */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, + + /* Cipher C022 */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_ECDH /* HMAC based TLS v1.2 ciphersuites from RFC5289 */ @@ -2808,6 +2953,9 @@ ssl3_new(SSL *s) s->s3 = s3; +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_init(s); +#endif s->method->ssl_clear(s); return (1); err: @@ -2850,6 +2998,9 @@ ssl3_free(SSL *s) } if (s->s3->handshake_dgst) ssl3_free_digest_list(s); +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_free(s); +#endif OPENSSL_cleanse(s->s3, sizeof *s->s3); OPENSSL_free(s->s3); s->s3 = NULL; @@ -2934,6 +3085,13 @@ ssl3_clear(SSL *s) #endif } +#ifndef OPENSSL_NO_SRP +static char * +srp_password_from_info_cb(SSL *s, void *arg) +{ + return BUF_strdup(s->srp_ctx.info); +} +#endif long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) @@ -3375,6 +3533,36 @@ ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) return 1; break; +#ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + if (ctx->srp_ctx.login != NULL) + OPENSSL_free(ctx->srp_ctx.login); + ctx->srp_ctx.login = NULL; + if (parg == NULL) + break; + if (strlen((const char *)parg) > 255 || strlen((const char *)parg) < 1) { + SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_SRP_USERNAME); + return 0; + } + if ((ctx->srp_ctx.login = BUF_strdup((char *)parg)) == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_INTERNAL_ERROR); + return 0; + } + break; + case SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD: + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = srp_password_from_info_cb; + ctx->srp_ctx.info = parg; + break; + case SSL_CTRL_SET_SRP_ARG: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_cb_arg = parg; + break; + + case SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH: + ctx->srp_ctx.strength = larg; + break; +#endif #endif /* !OPENSSL_NO_TLSEXT */ /* A Thawte special :-) */ @@ -3452,6 +3640,23 @@ ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int))fp; break; +#ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_SRP_VERIFY_PARAM_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_verify_param_callback = + (int (*)(SSL *, void *))fp; + break; + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.TLS_ext_srp_username_callback = + (int (*)(SSL *, int *, void *))fp; + break; + case SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB: + ctx->srp_ctx.srp_Mask|=SSL_kSRP; + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = + (char *(*)(SSL *, void *))fp; + break; +#endif #endif default: return (0); @@ -3557,6 +3762,10 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, mask_a = cert->mask_a; emask_k = cert->export_mask_k; emask_a = cert->export_mask_a; +#ifndef OPENSSL_NO_SRP + mask_k = cert->mask_k | s->srp_ctx.srp_Mask; + emask_k = cert->export_mask_k | s->srp_ctx.srp_Mask; +#endif #ifdef KSSL_DEBUG /* printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/ diff --git a/lib/libssl/src/ssl/s3_srvr.c b/lib/libssl/src/ssl/s3_srvr.c index 1a924f828e5..cc46e241d4f 100644 --- a/lib/libssl/src/ssl/s3_srvr.c +++ b/lib/libssl/src/ssl/s3_srvr.c @@ -180,6 +180,28 @@ static const SSL_METHOD return (NULL); } +#ifndef OPENSSL_NO_SRP +static int +ssl_check_srp_ext_ClientHello(SSL *s, int *al) +{ + int ret = SSL_ERROR_NONE; + + *al = SSL_AD_UNRECOGNIZED_NAME; + + if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) && + (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) { + if (s->srp_ctx.login == NULL) { + /* RFC 5054 says SHOULD reject, + we do so if There is no srp login name */ + ret = SSL3_AL_FATAL; + *al = SSL_AD_UNKNOWN_PSK_IDENTITY; + } else { + ret = SSL_srp_server_param_with_username(s, al); + } + } + return ret; +} +#endif IMPLEMENT_ssl3_meth_func(SSLv3_server_method, ssl3_accept, ssl_undefined_function, ssl3_get_server_method) @@ -317,6 +339,39 @@ ssl3_accept(SSL *s) if (ret <= 0) goto end; } +#ifndef OPENSSL_NO_SRP + { + int al; + if ((ret = + ssl_check_srp_ext_ClientHello(s, &al)) + < 0) { + /* + * Callback indicates further work to + * be done. + */ + s->rwstate = SSL_X509_LOOKUP; + goto end; + } + if (ret != SSL_ERROR_NONE) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + + /* + * This is not really an error but the + * only means for a client to detect + * whether srp is supported. + */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_SSL3_ACCEPT, + SSL_R_CLIENTHELLO_TLSEXT); + + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + + ret = -1; + goto end; + + } + } +#endif s->renegotiate = 2; s->state = SSL3_ST_SW_SRVR_HELLO_A; @@ -414,6 +469,10 @@ ssl3_accept(SSL *s) * hint if provided */ #ifndef OPENSSL_NO_PSK || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) +#endif +#ifndef OPENSSL_NO_SRP + /* SRP: send ServerKeyExchange */ + || (alg_k & SSL_kSRP) #endif || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH)) || (alg_k & SSL_kEECDH) @@ -1751,6 +1810,19 @@ ssl3_send_server_key_exchange(SSL *s) n += 2 + pskhintlen; } else #endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (type & SSL_kSRP) { + if ((s->srp_ctx.N == NULL) || (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, SSL_R_MISSING_SRP_PARAM); + goto err; + } + r[0] = s->srp_ctx.N; + r[1] = s->srp_ctx.g; + r[2] = s->srp_ctx.s; + r[3] = s->srp_ctx.B; + } else +#endif { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); @@ -1758,6 +1830,11 @@ ssl3_send_server_key_exchange(SSL *s) } for (i = 0; i < 4 && r[i] != NULL; i++) { nr[i] = BN_num_bytes(r[i]); +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) + n += 1 + nr[i]; + else +#endif n += 2 + nr[i]; } @@ -1783,6 +1860,12 @@ ssl3_send_server_key_exchange(SSL *s) p = &(d[4]); for (i = 0; i < 4 && r[i] != NULL; i++) { +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) { + *p = nr[i]; + p++; + } else +#endif s2n(nr[i], p); BN_bn2bin(r[i], p); p += nr[i]; @@ -2651,6 +2734,43 @@ ssl3_get_client_key_exchange(SSL *s) goto f_err; } else #endif +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + int param_len; + + n2s(p, i); + param_len = i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_SRP_A_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.A = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_BN_LIB); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = + SRP_generate_server_master_secret(s, + s->session->master_key)) < 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + p += i; + } else +#endif /* OPENSSL_NO_SRP */ if (alg_k & SSL_kGOST) { int ret = 0; EVP_PKEY_CTX *pkey_ctx; @@ -2731,7 +2851,9 @@ ssl3_get_client_key_exchange(SSL *s) return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) || defined(OPENSSL_NO_SRP) err: +#endif #ifndef OPENSSL_NO_ECDH EVP_PKEY_free(clnt_pub_pkey); EC_POINT_free(clnt_ecpoint); diff --git a/lib/libssl/src/ssl/ssl.h b/lib/libssl/src/ssl/ssl.h index 3f99de16166..d3e015e738c 100644 --- a/lib/libssl/src/ssl/ssl.h +++ b/lib/libssl/src/ssl/ssl.h @@ -533,6 +533,9 @@ struct ssl_session_st { 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 }; #endif @@ -682,6 +685,42 @@ void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, #define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) #define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +#ifndef OPENSSL_NO_SRP + +#ifndef OPENSSL_NO_SSL_INTERN + +typedef struct srp_ctx_st { + /* param for all the callbacks */ + void *SRP_cb_arg; + /* set client Hello login callback */ + int (*TLS_ext_srp_username_callback)(SSL *, int *, void *); + /* set SRP N/g param callback for verification */ + int (*SRP_verify_param_callback)(SSL *, void *); + /* set SRP client passwd callback */ + char *(*SRP_give_srp_client_pwd_callback)(SSL *, void *); + + char *login; + BIGNUM *N, *g, *s, *B, *A; + BIGNUM *a, *b, *v; + char *info; + int strength; + + unsigned long srp_Mask; +} SRP_CTX; + +#endif + +/* see tls_srp.c */ +int SSL_SRP_CTX_init(SSL *s); +int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx); +int SSL_SRP_CTX_free(SSL *ctx); +int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx); +int SSL_srp_server_param_with_username(SSL *s, int *ad); +int SRP_generate_server_master_secret(SSL *s, unsigned char *master_key); +int SRP_Calc_A_param(SSL *s); +int SRP_generate_client_master_secret(SSL *s, unsigned char *master_key); + +#endif #define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */ @@ -903,6 +942,9 @@ struct ssl_ctx_st { struct ssl3_buf_freelist_st *wbuf_freelist; struct ssl3_buf_freelist_st *rbuf_freelist; #endif +#ifndef OPENSSL_NO_SRP + SRP_CTX srp_ctx; /* ctx for SRP authentication */ +#endif #ifndef OPENSSL_NO_TLSEXT @@ -1306,6 +1348,9 @@ struct ssl_st { * 2 if we are a server and are inside a handshake * (i.e. not just sending a HelloRequest) */ +#ifndef OPENSSL_NO_SRP + SRP_CTX srp_ctx; /* ctx for SRP authentication */ +#endif }; #endif @@ -1754,6 +1799,24 @@ int SSL_set_trust(SSL *s, int trust); int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); +#ifndef OPENSSL_NO_SRP +int SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name); +int SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password); +int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength); +int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx, char *(*cb)(SSL *, void *)); +int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx, int (*cb)(SSL *, void *)); +int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx, int (*cb)(SSL *, int *, void *)); +int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg); + +int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g, BIGNUM *sa, BIGNUM *v, char *info); +int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass, const char *grp); + +BIGNUM *SSL_get_srp_g(SSL *s); +BIGNUM *SSL_get_srp_N(SSL *s); + +char *SSL_get_srp_username(SSL *s); +char *SSL_get_srp_userinfo(SSL *s); +#endif void SSL_free(SSL *ssl); int SSL_accept(SSL *ssl); diff --git a/lib/libssl/src/ssl/ssl_asn1.c b/lib/libssl/src/ssl/ssl_asn1.c index b1a3876c91a..28e295f6a44 100644 --- a/lib/libssl/src/ssl/ssl_asn1.c +++ b/lib/libssl/src/ssl/ssl_asn1.c @@ -113,6 +113,9 @@ typedef struct ssl_session_asn1_st { ASN1_OCTET_STRING psk_identity_hint; ASN1_OCTET_STRING psk_identity; #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + ASN1_OCTET_STRING srp_username; +#endif /* OPENSSL_NO_SRP */ } SSL_SESSION_ASN1; int @@ -129,6 +132,9 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) #ifndef OPENSSL_NO_COMP unsigned char cbuf; int v11 = 0; +#endif +#ifndef OPENSSL_NO_SRP + int v12 = 0; #endif long l; SSL_SESSION_ASN1 a; @@ -247,6 +253,13 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) a.psk_identity.data = (unsigned char *)(in->psk_identity); } #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) { + a.srp_username.length = strlen(in->srp_username); + a.srp_username.type = V_ASN1_OCTET_STRING; + a.srp_username.data = (unsigned char *)(in->srp_username); + } +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER); M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER); @@ -287,6 +300,10 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->psk_identity) M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING, 8, v8); #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, v12); +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_seq_total(); @@ -331,6 +348,10 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->compress_meth) M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING, 11, v11); #endif +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, v12); +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_finish(); } @@ -559,6 +580,18 @@ long length) } #endif +#ifndef OPENSSL_NO_SRP + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 12); + if (os.data) { + ret->srp_username = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->srp_username = NULL; +#endif /* OPENSSL_NO_SRP */ M_ASN1_D2I_Finish(a, SSL_SESSION_free, SSL_F_D2I_SSL_SESSION); } diff --git a/lib/libssl/src/ssl/ssl_ciph.c b/lib/libssl/src/ssl/ssl_ciph.c index 1a87cc255d8..4bd3be0d41f 100644 --- a/lib/libssl/src/ssl/ssl_ciph.c +++ b/lib/libssl/src/ssl/ssl_ciph.c @@ -724,7 +724,9 @@ ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *mkey |= SSL_kPSK; *auth |= SSL_aPSK; #endif +#ifdef OPENSSL_NO_SRP *mkey |= SSL_kSRP; +#endif /* Check for presence of GOST 34.10 algorithms, and if they * do not present, disable appropriate auth and key exchange */ if (!get_optional_pkey_id("gost94")) { diff --git a/lib/libssl/src/ssl/ssl_lib.c b/lib/libssl/src/ssl/ssl_lib.c index d0c79710ef1..a0882e45215 100644 --- a/lib/libssl/src/ssl/ssl_lib.c +++ b/lib/libssl/src/ssl/ssl_lib.c @@ -1823,6 +1823,9 @@ SSL_CTX ret->psk_client_callback = NULL; ret->psk_server_callback = NULL; #endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_init(ret); +#endif #ifndef OPENSSL_NO_BUF_FREELISTS ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT; ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST)); @@ -1962,6 +1965,9 @@ SSL_CTX_free(SSL_CTX *a) if (a->psk_identity_hint) OPENSSL_free(a->psk_identity_hint); #endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_free(a); +#endif #ifndef OPENSSL_NO_ENGINE if (a->client_cert_engine) ENGINE_finish(a->client_cert_engine); diff --git a/lib/libssl/src/ssl/ssl_sess.c b/lib/libssl/src/ssl/ssl_sess.c index 5c5ef4a312c..0b1c655820d 100644 --- a/lib/libssl/src/ssl/ssl_sess.c +++ b/lib/libssl/src/ssl/ssl_sess.c @@ -223,6 +223,9 @@ SSL_SESSION #ifndef OPENSSL_NO_PSK ss->psk_identity_hint = NULL; ss->psk_identity = NULL; +#endif +#ifndef OPENSSL_NO_SRP + ss->srp_username = NULL; #endif return (ss); } @@ -733,6 +736,10 @@ SSL_SESSION_free(SSL_SESSION *ss) OPENSSL_free(ss->psk_identity_hint); if (ss->psk_identity != NULL) OPENSSL_free(ss->psk_identity); +#endif +#ifndef OPENSSL_NO_SRP + if (ss->srp_username != NULL) + OPENSSL_free(ss->srp_username); #endif OPENSSL_cleanse(ss, sizeof(*ss)); OPENSSL_free(ss); diff --git a/lib/libssl/src/ssl/ssl_txt.c b/lib/libssl/src/ssl/ssl_txt.c index d3f304b73d9..91664ffe432 100644 --- a/lib/libssl/src/ssl/ssl_txt.c +++ b/lib/libssl/src/ssl/ssl_txt.c @@ -193,6 +193,12 @@ SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) if (BIO_printf(bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0) goto err; #endif +#ifndef OPENSSL_NO_SRP + if (BIO_puts(bp, "\n SRP username: ") + <= 0) goto err; + if (BIO_printf(bp, "%s", x->srp_username ? x->srp_username : "None") + <= 0) goto err; +#endif #ifndef OPENSSL_NO_TLSEXT if (x->tlsext_tick_lifetime_hint) { if (BIO_printf(bp, diff --git a/lib/libssl/src/ssl/ssltest.c b/lib/libssl/src/ssl/ssltest.c index 1d43f5a0e8b..771c50a3e1e 100644 --- a/lib/libssl/src/ssl/ssltest.c +++ b/lib/libssl/src/ssl/ssltest.c @@ -182,6 +182,9 @@ #ifndef OPENSSL_NO_DH #include #endif +#ifndef OPENSSL_NO_SRP +#include +#endif #include #define _XOPEN_SOURCE_EXTENDED 1 /* Or gethostname won't be declared properly @@ -231,6 +234,46 @@ static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len); #endif +#ifndef OPENSSL_NO_SRP +/* SRP client */ +/* This is a context that we pass to all callbacks */ +typedef struct srp_client_arg_st { + char *srppassin; + char *srplogin; +} SRP_CLIENT_ARG; + +#define PWD_STRLEN 1024 + +static char * +ssl_give_srp_client_pwd_cb(SSL *s, void *arg) +{ + SRP_CLIENT_ARG *srp_client_arg = (SRP_CLIENT_ARG *)arg; + return BUF_strdup((char *)srp_client_arg->srppassin); +} + +/* SRP server */ +/* This is a context that we pass to SRP server callbacks */ +typedef struct srp_server_arg_st { + char *expected_user; + char *pass; +} SRP_SERVER_ARG; + +static int +ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) +{ + SRP_SERVER_ARG *p = (SRP_SERVER_ARG *) arg; + + if (strcmp(p->expected_user, SSL_get_srp_username(s)) != 0) { + fprintf(stderr, "User %s doesn't exist\n", SSL_get_srp_username(s)); + return SSL3_AL_FATAL; + } + if (SSL_set_srp_server_param_pw(s, p->expected_user, p->pass, "1024") < 0) { + *ad = SSL_AD_INTERNAL_ERROR; + return SSL3_AL_FATAL; + } + return SSL_ERROR_NONE; +} +#endif static BIO *bio_err = NULL; static BIO *bio_stdout = NULL; @@ -276,6 +319,10 @@ sv_usage(void) #endif #ifndef OPENSSL_NO_PSK fprintf(stderr, " -psk arg - PSK in hex (without 0x)\n"); +#endif +#ifndef OPENSSL_NO_SRP + fprintf(stderr, " -srpuser user - SRP username to use\n"); + fprintf(stderr, " -srppass arg - password for 'user'\n"); #endif fprintf(stderr, " -ssl3 - use SSLv3\n"); fprintf(stderr, " -tls1 - use TLSv1\n"); @@ -451,6 +498,12 @@ main(int argc, char *argv[]) #endif #ifndef OPENSSL_NO_ECDH EC_KEY *ecdh = NULL; +#endif +#ifndef OPENSSL_NO_SRP + /* client */ + SRP_CLIENT_ARG srp_client_arg = {NULL, NULL}; + /* server */ + SRP_SERVER_ARG srp_server_arg = {NULL, NULL}; #endif int no_dhe = 0; int no_ecdhe = 0; @@ -541,6 +594,19 @@ main(int argc, char *argv[]) no_psk = 1; #endif } +#ifndef OPENSSL_NO_SRP + else if (strcmp(*argv, "-srpuser") == 0) { + if (--argc < 1) + goto bad; + srp_server_arg.expected_user = srp_client_arg.srplogin= *(++argv); + tls1 = 1; + } else if (strcmp(*argv, "-srppass") == 0) { + if (--argc < 1) + goto bad; + srp_server_arg.pass = srp_client_arg.srppassin= *(++argv); + tls1 = 1; + } +#endif else if (strcmp(*argv, "-ssl2") == 0) ssl2 = 1; else if (strcmp(*argv, "-tls1") == 0) @@ -848,6 +914,23 @@ bad: } #endif } +#ifndef OPENSSL_NO_SRP + if (srp_client_arg.srplogin) { + if (!SSL_CTX_set_srp_username(c_ctx, srp_client_arg.srplogin)) { + BIO_printf(bio_err, "Unable to set SRP username\n"); + goto end; + } + SSL_CTX_set_srp_cb_arg(c_ctx, &srp_client_arg); + SSL_CTX_set_srp_client_pwd_callback(c_ctx, ssl_give_srp_client_pwd_cb); + /*SSL_CTX_set_srp_strength(c_ctx, srp_client_arg.strength);*/ + } + + if (srp_server_arg.expected_user != NULL) { + SSL_CTX_set_verify(s_ctx, SSL_VERIFY_NONE, verify_callback); + SSL_CTX_set_srp_cb_arg(s_ctx, &srp_server_arg); + SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb); + } +#endif c_ssl = SSL_new(c_ctx); s_ssl = SSL_new(s_ctx); diff --git a/lib/libssl/src/ssl/t1_lib.c b/lib/libssl/src/ssl/t1_lib.c index c4eeb7a41d2..c3d62957ae3 100644 --- a/lib/libssl/src/ssl/t1_lib.c +++ b/lib/libssl/src/ssl/t1_lib.c @@ -427,6 +427,35 @@ unsigned char ret += el; } +#ifndef OPENSSL_NO_SRP + /* Add SRP username if there is one */ + if (s->srp_ctx.login != NULL) + { /* Add TLS extension SRP username to the Client Hello message */ + + int login_len = strlen(s->srp_ctx.login); + + if (login_len > 255 || login_len == 0) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + /* check for enough space. + 4 for the srp type type and entension length + 1 for the srp user identity + + srp user identity length + */ + if ((limit - ret - 5 - login_len) + < 0) return NULL; + + + /* fill in the extension */ + s2n(TLSEXT_TYPE_srp, ret); + s2n(login_len + 1, ret); + (*ret++) = (unsigned char) login_len; + memcpy(ret, s->srp_ctx.login, login_len); + ret += login_len; + } +#endif #ifndef OPENSSL_NO_EC if (s->tlsext_ecpointformatlist != NULL && @@ -1042,6 +1071,27 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, } } +#ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) { + if (size <= 0 || ((len = data[0])) != (size - 1)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->srp_ctx.login != NULL) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if ((s->srp_ctx.login = OPENSSL_malloc(len + 1)) == NULL) + return -1; + memcpy(s->srp_ctx.login, &data[1], len); + s->srp_ctx.login[len] = '\0'; + + if (strlen(s->srp_ctx.login) != len) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } +#endif #ifndef OPENSSL_NO_EC else if (type == TLSEXT_TYPE_ec_point_formats && diff --git a/lib/libssl/src/ssl/tls_srp.c b/lib/libssl/src/ssl/tls_srp.c new file mode 100644 index 00000000000..25ab73af9db --- /dev/null +++ b/lib/libssl/src/ssl/tls_srp.c @@ -0,0 +1,511 @@ +/* ssl/tls_srp.c */ +/* Written by Christophe Renou (christophe.renou@edelweb.fr) with + * the precious help of Peter Sylvester (peter.sylvester@edelweb.fr) + * for the EdelKey project and contributed to the OpenSSL project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include "ssl_locl.h" +#ifndef OPENSSL_NO_SRP + +#include +#include +#include + +int +SSL_CTX_SRP_CTX_free(struct ssl_ctx_st *ctx) { + if (ctx == NULL) + return 0; + OPENSSL_free(ctx->srp_ctx.login); + BN_free(ctx->srp_ctx.N); + BN_free(ctx->srp_ctx.g); + BN_free(ctx->srp_ctx.s); + BN_free(ctx->srp_ctx.B); + BN_free(ctx->srp_ctx.A); + BN_free(ctx->srp_ctx.a); + BN_free(ctx->srp_ctx.b); + BN_free(ctx->srp_ctx.v); + ctx->srp_ctx.TLS_ext_srp_username_callback = NULL; + ctx->srp_ctx.SRP_cb_arg = NULL; + ctx->srp_ctx.SRP_verify_param_callback = NULL; + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + ctx->srp_ctx.N = NULL; + ctx->srp_ctx.g = NULL; + ctx->srp_ctx.s = NULL; + ctx->srp_ctx.B = NULL; + ctx->srp_ctx.A = NULL; + ctx->srp_ctx.a = NULL; + ctx->srp_ctx.b = NULL; + ctx->srp_ctx.v = NULL; + ctx->srp_ctx.login = NULL; + ctx->srp_ctx.info = NULL; + ctx->srp_ctx.strength = SRP_MINIMAL_N; + ctx->srp_ctx.srp_Mask = 0; + return (1); +} + +int +SSL_SRP_CTX_free(struct ssl_st *s) { + if (s == NULL) + return 0; + OPENSSL_free(s->srp_ctx.login); + BN_free(s->srp_ctx.N); + BN_free(s->srp_ctx.g); + BN_free(s->srp_ctx.s); + BN_free(s->srp_ctx.B); + BN_free(s->srp_ctx.A); + BN_free(s->srp_ctx.a); + BN_free(s->srp_ctx.b); + BN_free(s->srp_ctx.v); + s->srp_ctx.TLS_ext_srp_username_callback = NULL; + s->srp_ctx.SRP_cb_arg = NULL; + s->srp_ctx.SRP_verify_param_callback = NULL; + s->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + s->srp_ctx.N = NULL; + s->srp_ctx.g = NULL; + s->srp_ctx.s = NULL; + s->srp_ctx.B = NULL; + s->srp_ctx.A = NULL; + s->srp_ctx.a = NULL; + s->srp_ctx.b = NULL; + s->srp_ctx.v = NULL; + s->srp_ctx.login = NULL; + s->srp_ctx.info = NULL; + s->srp_ctx.strength = SRP_MINIMAL_N; + s->srp_ctx.srp_Mask = 0; + return (1); +} + +int +SSL_SRP_CTX_init(struct ssl_st *s) { + SSL_CTX *ctx; + + if ((s == NULL) || ((ctx = s->ctx) == NULL)) + return 0; + s->srp_ctx.SRP_cb_arg = ctx->srp_ctx.SRP_cb_arg; + /* set client Hello login callback */ + s->srp_ctx.TLS_ext_srp_username_callback = ctx->srp_ctx.TLS_ext_srp_username_callback; + /* set SRP N/g param callback for verification */ + s->srp_ctx.SRP_verify_param_callback = ctx->srp_ctx.SRP_verify_param_callback; + /* set SRP client passwd callback */ + s->srp_ctx.SRP_give_srp_client_pwd_callback = ctx->srp_ctx.SRP_give_srp_client_pwd_callback; + + s->srp_ctx.N = NULL; + s->srp_ctx.g = NULL; + s->srp_ctx.s = NULL; + s->srp_ctx.B = NULL; + s->srp_ctx.A = NULL; + s->srp_ctx.a = NULL; + s->srp_ctx.b = NULL; + s->srp_ctx.v = NULL; + s->srp_ctx.login = NULL; + s->srp_ctx.info = ctx->srp_ctx.info; + s->srp_ctx.strength = ctx->srp_ctx.strength; + + if (((ctx->srp_ctx.N != NULL) && + ((s->srp_ctx.N = BN_dup(ctx->srp_ctx.N)) == NULL)) || + ((ctx->srp_ctx.g != NULL) && + ((s->srp_ctx.g = BN_dup(ctx->srp_ctx.g)) == NULL)) || + ((ctx->srp_ctx.s != NULL) && + ((s->srp_ctx.s = BN_dup(ctx->srp_ctx.s)) == NULL)) || + ((ctx->srp_ctx.B != NULL) && + ((s->srp_ctx.B = BN_dup(ctx->srp_ctx.B)) == NULL)) || + ((ctx->srp_ctx.A != NULL) && + ((s->srp_ctx.A = BN_dup(ctx->srp_ctx.A)) == NULL)) || + ((ctx->srp_ctx.a != NULL) && + ((s->srp_ctx.a = BN_dup(ctx->srp_ctx.a)) == NULL)) || + ((ctx->srp_ctx.v != NULL) && + ((s->srp_ctx.v = BN_dup(ctx->srp_ctx.v)) == NULL)) || + ((ctx->srp_ctx.b != NULL) && + ((s->srp_ctx.b = BN_dup(ctx->srp_ctx.b)) == NULL))) { + SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_BN_LIB); + goto err; + } + if ((ctx->srp_ctx.login != NULL) && + ((s->srp_ctx.login = BUF_strdup(ctx->srp_ctx.login)) == NULL)) { + SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_INTERNAL_ERROR); + goto err; + } + s->srp_ctx.srp_Mask = ctx->srp_ctx.srp_Mask; + + return (1); +err: + OPENSSL_free(s->srp_ctx.login); + BN_free(s->srp_ctx.N); + BN_free(s->srp_ctx.g); + BN_free(s->srp_ctx.s); + BN_free(s->srp_ctx.B); + BN_free(s->srp_ctx.A); + BN_free(s->srp_ctx.a); + BN_free(s->srp_ctx.b); + BN_free(s->srp_ctx.v); + return (0); +} + +int +SSL_CTX_SRP_CTX_init(struct ssl_ctx_st *ctx) { + if (ctx == NULL) + return 0; + + ctx->srp_ctx.SRP_cb_arg = NULL; + /* set client Hello login callback */ + ctx->srp_ctx.TLS_ext_srp_username_callback = NULL; + /* set SRP N/g param callback for verification */ + ctx->srp_ctx.SRP_verify_param_callback = NULL; + /* set SRP client passwd callback */ + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + + ctx->srp_ctx.N = NULL; + ctx->srp_ctx.g = NULL; + ctx->srp_ctx.s = NULL; + ctx->srp_ctx.B = NULL; + ctx->srp_ctx.A = NULL; + ctx->srp_ctx.a = NULL; + ctx->srp_ctx.b = NULL; + ctx->srp_ctx.v = NULL; + ctx->srp_ctx.login = NULL; + ctx->srp_ctx.srp_Mask = 0; + ctx->srp_ctx.info = NULL; + ctx->srp_ctx.strength = SRP_MINIMAL_N; + + return (1); +} + +/* server side */ +int +SSL_srp_server_param_with_username(SSL *s, int *ad) +{ + unsigned char b[SSL_MAX_MASTER_KEY_LENGTH]; + int al; + + *ad = SSL_AD_UNKNOWN_PSK_IDENTITY; + if ((s->srp_ctx.TLS_ext_srp_username_callback !=NULL) && + ((al = s->srp_ctx.TLS_ext_srp_username_callback(s, ad, + s->srp_ctx.SRP_cb_arg)) != SSL_ERROR_NONE)) + return al; + + *ad = SSL_AD_INTERNAL_ERROR; + if ((s->srp_ctx.N == NULL) || (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.v == NULL)) + return SSL3_AL_FATAL; + + if (RAND_bytes(b, sizeof(b)) <= 0) + return SSL3_AL_FATAL; + s->srp_ctx.b = BN_bin2bn(b, sizeof(b), NULL); + OPENSSL_cleanse(b, sizeof(b)); + + /* Calculate: B = (kv + g^b) % N */ + + return ((s->srp_ctx.B = SRP_Calc_B(s->srp_ctx.b, s->srp_ctx.N, s->srp_ctx.g, s->srp_ctx.v)) != NULL) ? SSL_ERROR_NONE : SSL3_AL_FATAL; +} + +/* If the server just has the raw password, make up a verifier entry on the fly */ +int +SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass, const char *grp) +{ + SRP_gN *GN = SRP_get_default_gN(grp); + if (GN == NULL) + return -1; + s->srp_ctx.N = BN_dup(GN->N); + s->srp_ctx.g = BN_dup(GN->g); + if (s->srp_ctx.v != NULL) { + BN_clear_free(s->srp_ctx.v); + s->srp_ctx.v = NULL; + } + if (s->srp_ctx.s != NULL) { + BN_clear_free(s->srp_ctx.s); + s->srp_ctx.s = NULL; + } + if (!SRP_create_verifier_BN(user, pass, &s->srp_ctx.s, &s->srp_ctx.v, + GN->N, GN->g)) + return -1; + + return 1; +} + +int +SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g, + BIGNUM *sa, BIGNUM *v, char *info) +{ + if (N != NULL) { + if (s->srp_ctx.N != NULL) { + if (!BN_copy(s->srp_ctx.N, N)) { + BN_free(s->srp_ctx.N); + s->srp_ctx.N = NULL; + } + } else + s->srp_ctx.N = BN_dup(N); + } + if (g != NULL) { + if (s->srp_ctx.g != NULL) { + if (!BN_copy(s->srp_ctx.g, g)) { + BN_free(s->srp_ctx.g); + s->srp_ctx.g = NULL; + } + } else + s->srp_ctx.g = BN_dup(g); + } + if (sa != NULL) { + if (s->srp_ctx.s != NULL) { + if (!BN_copy(s->srp_ctx.s, sa)) { + BN_free(s->srp_ctx.s); + s->srp_ctx.s = NULL; + } + } else + s->srp_ctx.s = BN_dup(sa); + } + if (v != NULL) { + if (s->srp_ctx.v != NULL) { + if (!BN_copy(s->srp_ctx.v, v)) { + BN_free(s->srp_ctx.v); + s->srp_ctx.v = NULL; + } + } else + s->srp_ctx.v = BN_dup(v); + } + s->srp_ctx.info = info; + + if (!(s->srp_ctx.N) || !(s->srp_ctx.g) || + !(s->srp_ctx.s) || !(s->srp_ctx.v)) + return -1; + + return 1; +} + +int +SRP_generate_server_master_secret(SSL *s, unsigned char *master_key) +{ + BIGNUM *K = NULL, *u = NULL; + int ret = -1, tmp_len; + unsigned char *tmp = NULL; + + if (!SRP_Verify_A_mod_N(s->srp_ctx.A, s->srp_ctx.N)) + goto err; + if (!(u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N))) + goto err; + if (!(K = SRP_Calc_server_key(s->srp_ctx.A, s->srp_ctx.v, u, s->srp_ctx.b, s->srp_ctx.N))) + goto err; + + tmp_len = BN_num_bytes(K); + if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) + goto err; + BN_bn2bin(K, tmp); + ret = s->method->ssl3_enc->generate_master_secret(s, master_key, tmp, tmp_len); +err: + if (tmp) { + OPENSSL_cleanse(tmp, tmp_len); + OPENSSL_free(tmp); + } + BN_clear_free(K); + BN_clear_free(u); + return ret; +} + +/* client side */ +int +SRP_generate_client_master_secret(SSL *s, unsigned char *master_key) +{ + BIGNUM *x = NULL, *u = NULL, *K = NULL; + int ret = -1, tmp_len; + char *passwd = NULL; + unsigned char *tmp = NULL; + + /* Checks if b % n == 0 + */ + if (SRP_Verify_B_mod_N(s->srp_ctx.B, s->srp_ctx.N) == 0) + goto err; + if (!(u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N))) + goto err; + if (s->srp_ctx.SRP_give_srp_client_pwd_callback == NULL) + goto err; + if (!(passwd = s->srp_ctx.SRP_give_srp_client_pwd_callback(s, + s->srp_ctx.SRP_cb_arg))) + goto err; + if (!(x = SRP_Calc_x(s->srp_ctx.s, s->srp_ctx.login, passwd))) + goto err; + if (!(K = SRP_Calc_client_key(s->srp_ctx.N, s->srp_ctx.B, s->srp_ctx.g, + x, s->srp_ctx.a, u))) + goto err; + + tmp_len = BN_num_bytes(K); + if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) goto err; + BN_bn2bin(K, tmp); + ret = s->method->ssl3_enc->generate_master_secret(s, master_key, + tmp, tmp_len); +err: + if (tmp) { + OPENSSL_cleanse(tmp, tmp_len); + OPENSSL_free(tmp); + } + BN_clear_free(K); + BN_clear_free(x); + if (passwd) { + OPENSSL_cleanse(passwd, strlen(passwd)); + OPENSSL_free(passwd); + } + BN_clear_free(u); + return ret; +} + +int +SRP_Calc_A_param(SSL *s) +{ + unsigned char rnd[SSL_MAX_MASTER_KEY_LENGTH]; + + if (BN_num_bits(s->srp_ctx.N) < s->srp_ctx.strength) + return -1; + + if (s->srp_ctx.SRP_verify_param_callback ==NULL && + !SRP_check_known_gN_param(s->srp_ctx.g, s->srp_ctx.N)) + return -1; + + RAND_bytes(rnd, sizeof(rnd)); + s->srp_ctx.a = BN_bin2bn(rnd, sizeof(rnd), s->srp_ctx.a); + OPENSSL_cleanse(rnd, sizeof(rnd)); + + if (!(s->srp_ctx.A = SRP_Calc_A(s->srp_ctx.a, s->srp_ctx.N, + s->srp_ctx.g))) + return -1; + + /* We can have a callback to verify SRP param!! */ + if (s->srp_ctx.SRP_verify_param_callback !=NULL) + return s->srp_ctx.SRP_verify_param_callback(s, + s->srp_ctx.SRP_cb_arg); + + return 1; +} + +BIGNUM +*SSL_get_srp_g(SSL *s) +{ + if (s->srp_ctx.g != NULL) + return s->srp_ctx.g; + return s->ctx->srp_ctx.g; +} + +BIGNUM +*SSL_get_srp_N(SSL *s) +{ + if (s->srp_ctx.N != NULL) + return s->srp_ctx.N; + return s->ctx->srp_ctx.N; +} + +char +*SSL_get_srp_username(SSL *s) +{ + if (s->srp_ctx.login != NULL) + return s->srp_ctx.login; + return s->ctx->srp_ctx.login; +} + +char +*SSL_get_srp_userinfo(SSL *s) +{ + if (s->srp_ctx.info != NULL) + return s->srp_ctx.info; + return s->ctx->srp_ctx.info; +} + +#define tls1_ctx_ctrl ssl3_ctx_ctrl +#define tls1_ctx_callback_ctrl ssl3_ctx_callback_ctrl + +int +SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME, 0, name); +} + +int +SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD, 0, password); +} + +int +SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH, strength, + NULL); +} + +int +SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx, int (*cb)(SSL *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_VERIFY_PARAM_CB, + (void (*)(void))cb); +} + +int +SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_SRP_ARG, 0, arg); +} + +int +SSL_CTX_set_srp_username_callback(SSL_CTX *ctx, + int (*cb)(SSL *, int *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB, + (void (*)(void))cb); +} + +int +SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx, char *(*cb)(SSL *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB, + (void (*)(void))cb); +} + +#endif diff --git a/lib/libssl/ssl.h b/lib/libssl/ssl.h index 3f99de16166..d3e015e738c 100644 --- a/lib/libssl/ssl.h +++ b/lib/libssl/ssl.h @@ -533,6 +533,9 @@ struct ssl_session_st { 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 }; #endif @@ -682,6 +685,42 @@ void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, #define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) #define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +#ifndef OPENSSL_NO_SRP + +#ifndef OPENSSL_NO_SSL_INTERN + +typedef struct srp_ctx_st { + /* param for all the callbacks */ + void *SRP_cb_arg; + /* set client Hello login callback */ + int (*TLS_ext_srp_username_callback)(SSL *, int *, void *); + /* set SRP N/g param callback for verification */ + int (*SRP_verify_param_callback)(SSL *, void *); + /* set SRP client passwd callback */ + char *(*SRP_give_srp_client_pwd_callback)(SSL *, void *); + + char *login; + BIGNUM *N, *g, *s, *B, *A; + BIGNUM *a, *b, *v; + char *info; + int strength; + + unsigned long srp_Mask; +} SRP_CTX; + +#endif + +/* see tls_srp.c */ +int SSL_SRP_CTX_init(SSL *s); +int SSL_CTX_SRP_CTX_init(SSL_CTX *ctx); +int SSL_SRP_CTX_free(SSL *ctx); +int SSL_CTX_SRP_CTX_free(SSL_CTX *ctx); +int SSL_srp_server_param_with_username(SSL *s, int *ad); +int SRP_generate_server_master_secret(SSL *s, unsigned char *master_key); +int SRP_Calc_A_param(SSL *s); +int SRP_generate_client_master_secret(SSL *s, unsigned char *master_key); + +#endif #define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */ @@ -903,6 +942,9 @@ struct ssl_ctx_st { struct ssl3_buf_freelist_st *wbuf_freelist; struct ssl3_buf_freelist_st *rbuf_freelist; #endif +#ifndef OPENSSL_NO_SRP + SRP_CTX srp_ctx; /* ctx for SRP authentication */ +#endif #ifndef OPENSSL_NO_TLSEXT @@ -1306,6 +1348,9 @@ struct ssl_st { * 2 if we are a server and are inside a handshake * (i.e. not just sending a HelloRequest) */ +#ifndef OPENSSL_NO_SRP + SRP_CTX srp_ctx; /* ctx for SRP authentication */ +#endif }; #endif @@ -1754,6 +1799,24 @@ int SSL_set_trust(SSL *s, int trust); int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); +#ifndef OPENSSL_NO_SRP +int SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name); +int SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password); +int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength); +int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx, char *(*cb)(SSL *, void *)); +int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx, int (*cb)(SSL *, void *)); +int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx, int (*cb)(SSL *, int *, void *)); +int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg); + +int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g, BIGNUM *sa, BIGNUM *v, char *info); +int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass, const char *grp); + +BIGNUM *SSL_get_srp_g(SSL *s); +BIGNUM *SSL_get_srp_N(SSL *s); + +char *SSL_get_srp_username(SSL *s); +char *SSL_get_srp_userinfo(SSL *s); +#endif void SSL_free(SSL *ssl); int SSL_accept(SSL *ssl); diff --git a/lib/libssl/ssl/Makefile b/lib/libssl/ssl/Makefile index 81b90e3fc36..6c8584e80d7 100644 --- a/lib/libssl/ssl/Makefile +++ b/lib/libssl/ssl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.36 2014/04/16 17:59:17 tedu Exp $ +# $OpenBSD: Makefile,v 1.37 2014/04/16 20:39:09 tedu Exp $ LIB= ssl @@ -19,7 +19,7 @@ SRCS=\ ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ ssl_ciph.c ssl_stat.c ssl_rsa.c \ ssl_asn1.c ssl_txt.c ssl_algs.c \ - bio_ssl.c ssl_err.c kssl.c t1_reneg.c + bio_ssl.c ssl_err.c kssl.c tls_srp.c t1_reneg.c SRCS+= s3_cbc.c HDRS= srtp.h ssl.h ssl2.h ssl3.h ssl23.h tls1.h dtls1.h kssl.h diff --git a/lib/libssl/ssl_asn1.c b/lib/libssl/ssl_asn1.c index b1a3876c91a..28e295f6a44 100644 --- a/lib/libssl/ssl_asn1.c +++ b/lib/libssl/ssl_asn1.c @@ -113,6 +113,9 @@ typedef struct ssl_session_asn1_st { ASN1_OCTET_STRING psk_identity_hint; ASN1_OCTET_STRING psk_identity; #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + ASN1_OCTET_STRING srp_username; +#endif /* OPENSSL_NO_SRP */ } SSL_SESSION_ASN1; int @@ -129,6 +132,9 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) #ifndef OPENSSL_NO_COMP unsigned char cbuf; int v11 = 0; +#endif +#ifndef OPENSSL_NO_SRP + int v12 = 0; #endif long l; SSL_SESSION_ASN1 a; @@ -247,6 +253,13 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) a.psk_identity.data = (unsigned char *)(in->psk_identity); } #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) { + a.srp_username.length = strlen(in->srp_username); + a.srp_username.type = V_ASN1_OCTET_STRING; + a.srp_username.data = (unsigned char *)(in->srp_username); + } +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER); M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER); @@ -287,6 +300,10 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->psk_identity) M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING, 8, v8); #endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, v12); +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_seq_total(); @@ -331,6 +348,10 @@ i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->compress_meth) M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING, 11, v11); #endif +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, v12); +#endif /* OPENSSL_NO_SRP */ M_ASN1_I2D_finish(); } @@ -559,6 +580,18 @@ long length) } #endif +#ifndef OPENSSL_NO_SRP + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 12); + if (os.data) { + ret->srp_username = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->srp_username = NULL; +#endif /* OPENSSL_NO_SRP */ M_ASN1_D2I_Finish(a, SSL_SESSION_free, SSL_F_D2I_SSL_SESSION); } diff --git a/lib/libssl/ssl_ciph.c b/lib/libssl/ssl_ciph.c index 1a87cc255d8..4bd3be0d41f 100644 --- a/lib/libssl/ssl_ciph.c +++ b/lib/libssl/ssl_ciph.c @@ -724,7 +724,9 @@ ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *mkey |= SSL_kPSK; *auth |= SSL_aPSK; #endif +#ifdef OPENSSL_NO_SRP *mkey |= SSL_kSRP; +#endif /* Check for presence of GOST 34.10 algorithms, and if they * do not present, disable appropriate auth and key exchange */ if (!get_optional_pkey_id("gost94")) { diff --git a/lib/libssl/ssl_lib.c b/lib/libssl/ssl_lib.c index d0c79710ef1..a0882e45215 100644 --- a/lib/libssl/ssl_lib.c +++ b/lib/libssl/ssl_lib.c @@ -1823,6 +1823,9 @@ SSL_CTX ret->psk_client_callback = NULL; ret->psk_server_callback = NULL; #endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_init(ret); +#endif #ifndef OPENSSL_NO_BUF_FREELISTS ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT; ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST)); @@ -1962,6 +1965,9 @@ SSL_CTX_free(SSL_CTX *a) if (a->psk_identity_hint) OPENSSL_free(a->psk_identity_hint); #endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_free(a); +#endif #ifndef OPENSSL_NO_ENGINE if (a->client_cert_engine) ENGINE_finish(a->client_cert_engine); diff --git a/lib/libssl/ssl_sess.c b/lib/libssl/ssl_sess.c index 5c5ef4a312c..0b1c655820d 100644 --- a/lib/libssl/ssl_sess.c +++ b/lib/libssl/ssl_sess.c @@ -223,6 +223,9 @@ SSL_SESSION #ifndef OPENSSL_NO_PSK ss->psk_identity_hint = NULL; ss->psk_identity = NULL; +#endif +#ifndef OPENSSL_NO_SRP + ss->srp_username = NULL; #endif return (ss); } @@ -733,6 +736,10 @@ SSL_SESSION_free(SSL_SESSION *ss) OPENSSL_free(ss->psk_identity_hint); if (ss->psk_identity != NULL) OPENSSL_free(ss->psk_identity); +#endif +#ifndef OPENSSL_NO_SRP + if (ss->srp_username != NULL) + OPENSSL_free(ss->srp_username); #endif OPENSSL_cleanse(ss, sizeof(*ss)); OPENSSL_free(ss); diff --git a/lib/libssl/ssl_txt.c b/lib/libssl/ssl_txt.c index d3f304b73d9..91664ffe432 100644 --- a/lib/libssl/ssl_txt.c +++ b/lib/libssl/ssl_txt.c @@ -193,6 +193,12 @@ SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) if (BIO_printf(bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0) goto err; #endif +#ifndef OPENSSL_NO_SRP + if (BIO_puts(bp, "\n SRP username: ") + <= 0) goto err; + if (BIO_printf(bp, "%s", x->srp_username ? x->srp_username : "None") + <= 0) goto err; +#endif #ifndef OPENSSL_NO_TLSEXT if (x->tlsext_tick_lifetime_hint) { if (BIO_printf(bp, diff --git a/lib/libssl/t1_lib.c b/lib/libssl/t1_lib.c index c4eeb7a41d2..c3d62957ae3 100644 --- a/lib/libssl/t1_lib.c +++ b/lib/libssl/t1_lib.c @@ -427,6 +427,35 @@ unsigned char ret += el; } +#ifndef OPENSSL_NO_SRP + /* Add SRP username if there is one */ + if (s->srp_ctx.login != NULL) + { /* Add TLS extension SRP username to the Client Hello message */ + + int login_len = strlen(s->srp_ctx.login); + + if (login_len > 255 || login_len == 0) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + /* check for enough space. + 4 for the srp type type and entension length + 1 for the srp user identity + + srp user identity length + */ + if ((limit - ret - 5 - login_len) + < 0) return NULL; + + + /* fill in the extension */ + s2n(TLSEXT_TYPE_srp, ret); + s2n(login_len + 1, ret); + (*ret++) = (unsigned char) login_len; + memcpy(ret, s->srp_ctx.login, login_len); + ret += login_len; + } +#endif #ifndef OPENSSL_NO_EC if (s->tlsext_ecpointformatlist != NULL && @@ -1042,6 +1071,27 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, } } +#ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) { + if (size <= 0 || ((len = data[0])) != (size - 1)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->srp_ctx.login != NULL) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if ((s->srp_ctx.login = OPENSSL_malloc(len + 1)) == NULL) + return -1; + memcpy(s->srp_ctx.login, &data[1], len); + s->srp_ctx.login[len] = '\0'; + + if (strlen(s->srp_ctx.login) != len) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } +#endif #ifndef OPENSSL_NO_EC else if (type == TLSEXT_TYPE_ec_point_formats &&