X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fsrp%2Fsrp_vfy.c;h=9505d4265e1dbbac4b6f7d89e2056b486edb3a90;hp=b85033b3058d6ccf61f8b4cbba0697265d11515a;hb=00db8c60aaecd2ff9b0a5d9fd10c7771a1e1a73e;hpb=4cffafe96786558f66e1900ac462f9ccba921132 diff --git a/crypto/srp/srp_vfy.c b/crypto/srp/srp_vfy.c index b85033b305..9505d4265e 100644 --- a/crypto/srp/srp_vfy.c +++ b/crypto/srp/srp_vfy.c @@ -2,7 +2,7 @@ * Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2004, EdelKey Project. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -13,36 +13,164 @@ #ifndef OPENSSL_NO_SRP # include "internal/cryptlib.h" +# include "crypto/evp.h" # include # include # include # include # include # include +# include # define SRP_RANDOM_SALT_LEN 20 # define MAX_LEN 2500 +/* + * Note that SRP uses its own variant of base 64 encoding. A different base64 + * alphabet is used and no padding '=' characters are added. Instead we pad to + * the front with 0 bytes and subsequently strip off leading encoded padding. + * This variant is used for compatibility with other SRP implementations - + * notably libsrp, but also others. It is also required for backwards + * compatibility in order to load verifier files from other OpenSSL versions. + */ + /* * Convert a base64 string into raw byte array representation. + * Returns the length of the decoded data, or -1 on error. */ static int t_fromb64(unsigned char *a, size_t alen, const char *src) { - size_t size = strlen(src); + EVP_ENCODE_CTX *ctx; + int outl = 0, outl2 = 0; + size_t size, padsize; + const unsigned char *pad = (const unsigned char *)"00"; + + while (*src == ' ' || *src == '\t' || *src == '\n') + ++src; + size = strlen(src); + padsize = 4 - (size & 3); + padsize &= 3; /* Four bytes in src become three bytes output. */ - if (size > INT_MAX || (size / 4) * 3 > alen) + if (size > INT_MAX || ((size + padsize) / 4) * 3 > alen) return -1; - return EVP_DecodeBlock(a, (unsigned char *)src, (int)size); + ctx = EVP_ENCODE_CTX_new(); + if (ctx == NULL) + return -1; + + /* + * This should never occur because 1 byte of data always requires 2 bytes of + * encoding, i.e. + * 0 bytes unencoded = 0 bytes encoded + * 1 byte unencoded = 2 bytes encoded + * 2 bytes unencoded = 3 bytes encoded + * 3 bytes unencoded = 4 bytes encoded + * 4 bytes unencoded = 6 bytes encoded + * etc + */ + if (padsize == 3) { + outl = -1; + goto err; + } + + /* Valid padsize values are now 0, 1 or 2 */ + + EVP_DecodeInit(ctx); + evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_USE_SRP_ALPHABET); + + /* Add any encoded padding that is required */ + if (padsize != 0 + && EVP_DecodeUpdate(ctx, a, &outl, pad, padsize) < 0) { + outl = -1; + goto err; + } + if (EVP_DecodeUpdate(ctx, a, &outl2, (const unsigned char *)src, size) < 0) { + outl = -1; + goto err; + } + outl += outl2; + EVP_DecodeFinal(ctx, a + outl, &outl2); + outl += outl2; + + /* Strip off the leading padding */ + if (padsize != 0) { + if ((int)padsize >= outl) { + outl = -1; + goto err; + } + + /* + * If we added 1 byte of padding prior to encoding then we have 2 bytes + * of "real" data which gets spread across 4 encoded bytes like this: + * (6 bits pad)(2 bits pad | 4 bits data)(6 bits data)(6 bits data) + * So 1 byte of pre-encoding padding results in 1 full byte of encoded + * padding. + * If we added 2 bytes of padding prior to encoding this gets encoded + * as: + * (6 bits pad)(6 bits pad)(4 bits pad | 2 bits data)(6 bits data) + * So 2 bytes of pre-encoding padding results in 2 full bytes of encoded + * padding, i.e. we have to strip the same number of bytes of padding + * from the encoded data as we added to the pre-encoded data. + */ + memmove(a, a + padsize, outl - padsize); + outl -= padsize; + } + + err: + EVP_ENCODE_CTX_free(ctx); + + return outl; } /* * Convert a raw byte string into a null-terminated base64 ASCII string. + * Returns 1 on success or 0 on error. */ -static void t_tob64(char *dst, const unsigned char *src, int size) +static int t_tob64(char *dst, const unsigned char *src, int size) { - EVP_EncodeBlock((unsigned char *)dst, src, size); + EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); + int outl = 0, outl2 = 0; + unsigned char pad[2] = {0, 0}; + size_t leadz = 0; + + if (ctx == NULL) + return 0; + + EVP_EncodeInit(ctx); + evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_NO_NEWLINES + | EVP_ENCODE_CTX_USE_SRP_ALPHABET); + + /* + * We pad at the front with zero bytes until the length is a multiple of 3 + * so that EVP_EncodeUpdate/EVP_EncodeFinal does not add any of its own "=" + * padding + */ + leadz = 3 - (size % 3); + if (leadz != 3 + && !EVP_EncodeUpdate(ctx, (unsigned char *)dst, &outl, pad, + leadz)) { + EVP_ENCODE_CTX_free(ctx); + return 0; + } + + if (!EVP_EncodeUpdate(ctx, (unsigned char *)dst + outl, &outl2, src, + size)) { + EVP_ENCODE_CTX_free(ctx); + return 0; + } + outl += outl2; + EVP_EncodeFinal(ctx, (unsigned char *)dst + outl, &outl2); + outl += outl2; + + /* Strip the encoded padding at the front */ + if (leadz != 3) { + memmove(dst, dst + leadz, outl - leadz); + dst[outl - leadz] = '\0'; + } + + EVP_ENCODE_CTX_free(ctx); + return 1; } void SRP_user_pwd_free(SRP_user_pwd *user_pwd) @@ -56,11 +184,14 @@ void SRP_user_pwd_free(SRP_user_pwd *user_pwd) OPENSSL_free(user_pwd); } -static SRP_user_pwd *SRP_user_pwd_new(void) +SRP_user_pwd *SRP_user_pwd_new(void) { - SRP_user_pwd *ret = OPENSSL_malloc(sizeof(*ret)); - if (ret == NULL) + SRP_user_pwd *ret; + + if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) { + /* SRPerr(SRP_F_SRP_USER_PWD_NEW, ERR_R_MALLOC_FAILURE); */ /*ckerr_ignore*/ return NULL; + } ret->N = NULL; ret->g = NULL; ret->s = NULL; @@ -70,16 +201,18 @@ static SRP_user_pwd *SRP_user_pwd_new(void) return ret; } -static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, - const BIGNUM *N) +void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, + const BIGNUM *N) { vinfo->N = N; vinfo->g = g; } -static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id, - const char *info) +int SRP_user_pwd_set1_ids(SRP_user_pwd *vinfo, const char *id, + const char *info) { + OPENSSL_free(vinfo->id); + OPENSSL_free(vinfo->info); if (id != NULL && NULL == (vinfo->id = OPENSSL_strdup(id))) return 0; return (info == NULL || NULL != (vinfo->info = OPENSSL_strdup(info))); @@ -112,8 +245,10 @@ static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, return 0; } -static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) +int SRP_user_pwd_set0_sv(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) { + BN_free(vinfo->s); + BN_clear_free(vinfo->v); vinfo->v = v; vinfo->s = s; return (vinfo->s != NULL && vinfo->v != NULL); @@ -129,8 +264,8 @@ static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src) return NULL; SRP_user_pwd_set_gN(ret, src->g, src->N); - if (!SRP_user_pwd_set_ids(ret, src->id, src->info) - || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) { + if (!SRP_user_pwd_set1_ids(ret, src->id, src->info) + || !SRP_user_pwd_set0_sv(ret, BN_dup(src->s), BN_dup(src->v))) { SRP_user_pwd_free(ret); return NULL; } @@ -209,12 +344,13 @@ static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) int i; SRP_gN *gN; - if (gN_tab != NULL) + if (gN_tab != NULL) { for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { gN = sk_SRP_gN_value(gN_tab, i); if (gN && (id == NULL || strcmp(gN->id, id) == 0)) return gN; } + } return SRP_get_default_gN(id); } @@ -243,9 +379,13 @@ static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) } /* - * this function parses verifier file. Format is: - * string(index):base64(N):base64(g):0 - * string(username):base64(v):base64(salt):int(index) + * This function parses the verifier file generated by the srp app. + * The format for each entry is: + * V base64(verifier) base64(salt) username gNid userinfo(optional) + * or + * I base64(N) base64(g) + * Note that base64 is the SRP variant of base64 encoding described + * in t_fromb64(). */ int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) @@ -310,7 +450,7 @@ int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) goto err; SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); - if (!SRP_user_pwd_set_ids + if (!SRP_user_pwd_set1_ids (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) goto err; @@ -378,7 +518,14 @@ static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username) return NULL; } -# if OPENSSL_API_COMPAT < 0x10100000L +int SRP_VBASE_add0_user(SRP_VBASE *vb, SRP_user_pwd *user_pwd) +{ + if (sk_SRP_user_pwd_push(vb->users_pwd, user_pwd) <= 0) + return 0; + return 1; +} + +# ifndef OPENSSL_NO_DEPRECATED_1_1_0 /* * DEPRECATED: use SRP_VBASE_get1_by_user instead. * This method ignores the configured seed and fails for an unknown user. @@ -419,7 +566,7 @@ SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); - if (!SRP_user_pwd_set_ids(user, username, NULL)) + if (!SRP_user_pwd_set1_ids(user, username, NULL)) goto err; if (RAND_priv_bytes(digv, SHA_DIGEST_LENGTH) <= 0) @@ -433,7 +580,7 @@ SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) goto err; EVP_MD_CTX_free(ctxt); ctxt = NULL; - if (SRP_user_pwd_set_sv_BN(user, + if (SRP_user_pwd_set0_sv(user, BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) return user; @@ -467,14 +614,18 @@ char *SRP_create_verifier(const char *user, const char *pass, char **salt, if ((len = t_fromb64(tmp, sizeof(tmp), N)) <= 0) goto err; N_bn_alloc = BN_bin2bn(tmp, len, NULL); + if (N_bn_alloc == NULL) + goto err; N_bn = N_bn_alloc; if ((len = t_fromb64(tmp, sizeof(tmp) ,g)) <= 0) goto err; g_bn_alloc = BN_bin2bn(tmp, len, NULL); + if (g_bn_alloc == NULL) + goto err; g_bn = g_bn_alloc; defgNid = "*"; } else { - SRP_gN *gN = SRP_get_gN_by_id(g, NULL); + SRP_gN *gN = SRP_get_default_gN(g); if (gN == NULL) goto err; N_bn = gN->N; @@ -492,15 +643,19 @@ char *SRP_create_verifier(const char *user, const char *pass, char **salt, goto err; s = BN_bin2bn(tmp2, len, NULL); } + if (s == NULL) + goto err; if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) goto err; - BN_bn2bin(v, tmp); + if (BN_bn2bin(v, tmp) < 0) + goto err; vfsize = BN_num_bytes(v) * 2; if (((vf = OPENSSL_malloc(vfsize)) == NULL)) goto err; - t_tob64(vf, tmp, BN_num_bytes(v)); + if (!t_tob64(vf, tmp, BN_num_bytes(v))) + goto err; if (*salt == NULL) { char *tmp_salt; @@ -508,7 +663,10 @@ char *SRP_create_verifier(const char *user, const char *pass, char **salt, if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { goto err; } - t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); + if (!t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN)) { + OPENSSL_free(tmp_salt); + goto err; + } *salt = tmp_salt; } @@ -555,11 +713,15 @@ int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, goto err; salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); + if (salttmp == NULL) + goto err; } else { salttmp = *salt; } x = SRP_Calc_x(salttmp, user, pass); + if (x == NULL) + goto err; *verifier = BN_new(); if (*verifier == NULL)