diff --git a/CHANGES b/CHANGES index 48537e854e776fe0e0c8b42b86d9d8b8fb91252d..e3362efa40c7bc88bd367ab7163d17ea85eb8360 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) Add support for canonical generation of DSA parameter 'g'. See + FIPS 186-3 A.2.3. + *) Add support for HMAC DRBG from SP800-90. Update algorithm and POST to handle HMAC cases. [Steve Henson] diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c index a4a0421beff4aba1175ff4d1ce31d7121c30d137..2a92d069cf2a7289b16ca2a3c635322162323e94 100644 --- a/crypto/dsa/dsa_gen.c +++ b/crypto/dsa/dsa_gen.c @@ -452,11 +452,11 @@ int fips_check_dsa_prng(DSA *dsa, size_t L, size_t N) int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len, - unsigned char *seed_out, + int idx, unsigned char *seed_out, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb) { int ok=-1; - unsigned char *seed = NULL; + unsigned char *seed = NULL, *seed_tmp = NULL; unsigned char md[EVP_MAX_MD_SIZE]; int mdsize; BIGNUM *r0,*W,*X,*c,*test; @@ -466,8 +466,11 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, int counter=0; int r=0; BN_CTX *ctx=NULL; + EVP_MD_CTX mctx; unsigned int h=2; + EVP_MD_CTX_init(&mctx); + #ifdef OPENSSL_FIPS if(FIPS_selftest_failed()) { @@ -497,7 +500,12 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, seed = OPENSSL_malloc(seed_len); - if (!seed) + if (seed_out) + seed_tmp = seed_out; + else + seed_tmp = OPENSSL_malloc(seed_len); + + if (!seed || !seed_tmp) goto err; if (seed_in) @@ -513,12 +521,24 @@ int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, r0 = BN_CTX_get(ctx); g = BN_CTX_get(ctx); W = BN_CTX_get(ctx); - q = BN_CTX_get(ctx); X = BN_CTX_get(ctx); c = BN_CTX_get(ctx); - p = BN_CTX_get(ctx); test = BN_CTX_get(ctx); + /* if p, q already supplied generate g only */ + if (ret->p && ret->q) + { + p = ret->p; + q = ret->q; + memcpy(seed_tmp, seed, seed_len); + goto g_only; + } + else + { + p = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + } + if (!BN_lshift(test,BN_value_one(),L-1)) goto err; for (;;) @@ -648,21 +668,50 @@ end: if(!BN_GENCB_call(cb, 2, 1)) goto err; + g_only: + /* We now need to generate g */ /* Set r0=(p-1)/q */ if (!BN_sub(test,p,BN_value_one())) goto err; if (!BN_div(r0,NULL,test,q,ctx)) goto err; - if (!BN_set_word(test,h)) goto err; + if (idx < 0) + { + if (!BN_set_word(test,h)) + goto err; + } + else + h = 1; if (!BN_MONT_CTX_set(mont,p,ctx)) goto err; for (;;) { + static const unsigned char ggen[4] = {0x67,0x67,0x65,0x6e}; + if (idx >= 0) + { + md[0] = idx & 0xff; + md[1] = (h >> 8) & 0xff; + md[2] = h & 0xff; + if (!EVP_DigestInit_ex(&mctx, evpmd, NULL)) + goto err; + if (!EVP_DigestUpdate(&mctx, seed_tmp, seed_len)) + goto err; + if (!EVP_DigestUpdate(&mctx, ggen, sizeof(ggen))) + goto err; + if (!EVP_DigestUpdate(&mctx, md, 3)) + goto err; + if (!EVP_DigestFinal_ex(&mctx, md, NULL)) + goto err; + if (!BN_bin2bn(md, mdsize, test)) + goto err; + } /* g=test^r0%p */ if (!BN_mod_exp_mont(g,test,r0,p,ctx,mont)) goto err; if (!BN_is_one(g)) break; - if (!BN_add(test,test,BN_value_one())) goto err; + if (idx < 0 && !BN_add(test,test,BN_value_one())) goto err; h++; + if ( idx >= 0 && h > 0xffff) + goto err; } if(!BN_GENCB_call(cb, 3, 1)) @@ -672,11 +721,17 @@ end: err: if (ok == 1) { - if(ret->p) BN_free(ret->p); - if(ret->q) BN_free(ret->q); + if (p != ret->p) + { + if(ret->p) BN_free(ret->p); + ret->p=BN_dup(p); + } + if (q != ret->q) + { + if(ret->q) BN_free(ret->q); + ret->q=BN_dup(q); + } if(ret->g) BN_free(ret->g); - ret->p=BN_dup(p); - ret->q=BN_dup(q); ret->g=BN_dup(g); if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { @@ -688,12 +743,53 @@ err: } if (seed) OPENSSL_free(seed); + if (seed_out != seed_tmp) + OPENSSL_free(seed_tmp); if(ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } if (mont != NULL) BN_MONT_CTX_free(mont); + EVP_MD_CTX_cleanup(&mctx); return ok; } + +int dsa_paramgen_check_g(DSA *dsa) + { + BN_CTX *ctx; + BIGNUM *tmp; + BN_MONT_CTX *mont = NULL; + int rv = -1; + ctx = BN_CTX_new(); + if (!ctx) + return -1; + BN_CTX_start(ctx); + if (BN_cmp(dsa->g, BN_value_one()) <= 0) + return 0; + if (BN_cmp(dsa->g, dsa->p) >= 0) + return 0; + tmp = BN_CTX_get(ctx); + if (!tmp) + goto err; + if ((mont=BN_MONT_CTX_new()) == NULL) + goto err; + if (!BN_MONT_CTX_set(mont,dsa->p,ctx)) + goto err; + /* Work out g^q mod p */ + if (!BN_mod_exp_mont(tmp,dsa->g,dsa->q, dsa->p, ctx, mont)) + goto err; + if (!BN_cmp(tmp, BN_value_one())) + rv = 1; + else + rv = 0; + err: + BN_CTX_end(ctx); + if (mont) + BN_MONT_CTX_free(mont); + BN_CTX_free(ctx); + return rv; + + } + #endif diff --git a/crypto/dsa/dsa_locl.h b/crypto/dsa/dsa_locl.h index 4e07c7cbaba2f7b2f62bbf5f64750c2c241ffc61..f385a7e86128290390bbdb98d803dbc01aae515d 100644 --- a/crypto/dsa/dsa_locl.h +++ b/crypto/dsa/dsa_locl.h @@ -59,7 +59,9 @@ int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, unsigned char *seed_out, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); -int dsa_builtin_paramgen2(DSA *ret, size_t bits, size_t qbits, +int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len, - unsigned char *seed_out, + int idx, unsigned char *seed_out, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); + +int dsa_paramgen_check_g(DSA *dsa); diff --git a/fips/dsa/fips_dssvs.c b/fips/dsa/fips_dssvs.c index b6dc56dbdc652630923206d1f139dca412b14511..ce1bc18f5304ea6f64063e3d83c5e6ea5396d8a1 100644 --- a/fips/dsa/fips_dssvs.c +++ b/fips/dsa/fips_dssvs.c @@ -111,9 +111,9 @@ int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len, unsigned char *seed_out, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); -int dsa_builtin_paramgen2(DSA *ret, size_t bits, size_t qbits, +int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len, - unsigned char *seed_out, + int idx, unsigned char *seed_out, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); static void pqg(FILE *in, FILE *out) @@ -160,7 +160,7 @@ static void pqg(FILE *in, FILE *out) exit(1); } if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, md, - NULL, 0, seed, + NULL, 0, -1, seed, &counter, &h, NULL) <= 0) { fprintf(stderr, "Parameter Generation error\n"); @@ -191,8 +191,8 @@ static void pqgver(FILE *in, FILE *out) DSA *dsa=NULL; int dsa2, L, N, part_test = 0; const EVP_MD *md = NULL; - int seedlen=-1; - unsigned char seed[1024]; + int seedlen=-1, idxlen, idx = -1; + unsigned char seed[1024], idtmp[1024]; while(fgets(buf,sizeof buf,in) != NULL) { @@ -221,7 +221,8 @@ static void pqgver(FILE *in, FILE *out) q=hex2bn(value); else if(!strcmp(keyword,"G")) g=hex2bn(value); - else if(!strcmp(keyword,"Seed")) + else if(!strcmp(keyword,"Seed") + || !strcmp(keyword,"domain_parameter_seed")) { seedlen = hex2bin(value, seed); if (!dsa2 && seedlen != 20) @@ -229,9 +230,21 @@ static void pqgver(FILE *in, FILE *out) fprintf(stderr, "Seed parse length error\n"); exit (1); } + if (idx > 0) + part_test = 1; + } + else if(!strcmp(keyword,"index")) + { + idxlen = hex2bin(value, idtmp); + if (idxlen != 1) + { + fprintf(stderr, "Index value error\n"); + exit (1); + } + idx = idtmp[0]; } else if(!strcmp(keyword,"c")) - counter =atoi(buf+4); + counter = atoi(buf+4); partial: if(!strcmp(keyword,"H") || part_test) { @@ -243,6 +256,11 @@ static void pqgver(FILE *in, FILE *out) exit (1); } dsa = FIPS_dsa_new(); + if (idx >= 0) + { + dsa->p = BN_dup(p); + dsa->q = BN_dup(q); + } if (!dsa2 && !dsa_builtin_paramgen(dsa, L, N, md, seed, seedlen, NULL, &counter2, &h2, NULL)) @@ -251,13 +269,20 @@ static void pqgver(FILE *in, FILE *out) exit(1); } if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, md, - seed, seedlen, NULL, + seed, seedlen, idx, NULL, &counter2, &h2, NULL) < 0) { fprintf(stderr, "Parameter Generation error\n"); exit(1); } - if (BN_cmp(dsa->p, p) || BN_cmp(dsa->q, q) || + if (idx >= 0) + { + if (BN_cmp(dsa->g, g)) + fprintf(out, "Result = F\n"); + else + fprintf(out, "Result = P\n"); + } + else if (BN_cmp(dsa->p, p) || BN_cmp(dsa->q, q) || (!part_test && ((BN_cmp(dsa->g, g) || (counter != counter2) || (h != h2))))) fprintf(out, "Result = F\n"); @@ -273,9 +298,11 @@ static void pqgver(FILE *in, FILE *out) dsa = NULL; if (part_test) { - fputs(buf,out); + if (idx == -1) + fputs(buf,out); part_test = 0; } + idx = -1; } } } @@ -436,7 +463,7 @@ static void keypair(FILE *in, FILE *out) fprintf(stderr, "Parameter Generation error\n"); exit(1); } - if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, NULL, NULL, 0, + if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, NULL, NULL, 0, -1, NULL, NULL, NULL, NULL) <= 0) { fprintf(stderr, "Parameter Generation error\n"); @@ -493,7 +520,7 @@ static void siggen(FILE *in, FILE *out) fprintf(stderr, "Parameter Generation error\n"); exit(1); } - if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, md, NULL, 0, + if (dsa2 && dsa_builtin_paramgen2(dsa, L, N, md, NULL, 0, -1, NULL, NULL, NULL, NULL) <= 0) { fprintf(stderr, "Parameter Generation error\n");