add back SRP. i was being too greedy.
authortedu <tedu@openbsd.org>
Wed, 16 Apr 2014 20:39:09 +0000 (20:39 +0000)
committertedu <tedu@openbsd.org>
Wed, 16 Apr 2014 20:39:09 +0000 (20:39 +0000)
23 files changed:
lib/libssl/s3_clnt.c
lib/libssl/s3_lib.c
lib/libssl/s3_srvr.c
lib/libssl/src/ssl/s3_clnt.c
lib/libssl/src/ssl/s3_lib.c
lib/libssl/src/ssl/s3_srvr.c
lib/libssl/src/ssl/ssl.h
lib/libssl/src/ssl/ssl_asn1.c
lib/libssl/src/ssl/ssl_ciph.c
lib/libssl/src/ssl/ssl_lib.c
lib/libssl/src/ssl/ssl_sess.c
lib/libssl/src/ssl/ssl_txt.c
lib/libssl/src/ssl/ssltest.c
lib/libssl/src/ssl/t1_lib.c
lib/libssl/src/ssl/tls_srp.c [new file with mode: 0644]
lib/libssl/ssl.h
lib/libssl/ssl/Makefile
lib/libssl/ssl_asn1.c
lib/libssl/ssl_ciph.c
lib/libssl/ssl_lib.c
lib/libssl/ssl_sess.c
lib/libssl/ssl_txt.c
lib/libssl/t1_lib.c

index 1589cdc..88be294 100644 (file)
@@ -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];
index f56dbe2..68a4b8c 100644 (file)
@@ -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);*/
index 1a924f8..cc46e24 100644 (file)
@@ -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);
index 1589cdc..88be294 100644 (file)
@@ -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];
index f56dbe2..68a4b8c 100644 (file)
@@ -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);*/
index 1a924f8..cc46e24 100644 (file)
@@ -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);
index 3f99de1..d3e015e 100644 (file)
@@ -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);
index b1a3876..28e295f 100644 (file)
@@ -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);
 }
index 1a87cc2..4bd3be0 100644 (file)
@@ -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")) {
index d0c7971..a0882e4 100644 (file)
@@ -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);
index 5c5ef4a..0b1c655 100644 (file)
@@ -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);
index d3f304b..91664ff 100644 (file)
@@ -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,
index 1d43f5a..771c50a 100644 (file)
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
+#ifndef OPENSSL_NO_SRP
+#include <openssl/srp.h>
+#endif
 #include <openssl/bn.h>
 
 #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);
index c4eeb7a..c3d6295 100644 (file)
@@ -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 (file)
index 0000000..25ab73a
--- /dev/null
@@ -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 <openssl/rand.h>
+#include <openssl/srp.h>
+#include <openssl/err.h>
+
+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
index 3f99de1..d3e015e 100644 (file)
@@ -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);
index 81b90e3..6c8584e 100644 (file)
@@ -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
index b1a3876..28e295f 100644 (file)
@@ -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);
 }
index 1a87cc2..4bd3be0 100644 (file)
@@ -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")) {
index d0c7971..a0882e4 100644 (file)
@@ -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);
index 5c5ef4a..0b1c655 100644 (file)
@@ -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);
index d3f304b..91664ff 100644 (file)
@@ -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,
index c4eeb7a..c3d6295 100644 (file)
@@ -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 &&