/* dsa-keygen.c * * Generation of DSA keypairs */ /* nettle, low-level cryptographics library * * Copyright (C) 2013 Red Hat * * The nettle library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * The nettle library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the nettle library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02111-1301, USA. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include /* This validates the given p, q, g params using the provided * dss_params_validation_seeds. * * The hash function used is SHA384. * * pub: The output public key * key: The output private key * cert: A certificate that can be used to verify the generated parameters * index: 1 for digital signatures (DSA), 2 for key establishment (DH) * */ int dsa_validate_dss_pqg(struct dsa_params *pub, struct dss_params_validation_seeds *cert, unsigned index) { int ret; uint8_t domain_seed[MAX_PVP_SEED_SIZE*3]; unsigned domain_seed_size = 0; ret = _dsa_validate_dss_pq(pub, cert); if (ret == 0) return 0; domain_seed_size = cert->seed_length + cert->qseed_length + cert->pseed_length; memcpy(domain_seed, cert->seed, cert->seed_length); memcpy(&domain_seed[cert->seed_length], cert->pseed, cert->pseed_length); memcpy(&domain_seed[cert->seed_length+cert->pseed_length], cert->qseed, cert->qseed_length); ret = _dsa_validate_dss_g(pub, domain_seed_size, domain_seed, index); if (ret == 0) return 0; return 1; } int _dsa_validate_dss_g(struct dsa_params *pub, unsigned domain_seed_size, const uint8_t *domain_seed, unsigned index) { int ret; unsigned p_bits, q_bits; struct dsa_params pub2; mpz_t r; p_bits = mpz_sizeinbase(pub->p, 2); q_bits = mpz_sizeinbase(pub->q, 2); ret = _dsa_check_qp_sizes(q_bits, p_bits, 0); if (ret == 0) { return 0; } mpz_init(r); dsa_params_init(&pub2); mpz_set(pub2.p, pub->p); mpz_set(pub2.q, pub->q); /* verify g */ if (index > 255) { goto fail; } /* 2<= g <= p-1 */ mpz_set(r, pub->p); mpz_sub_ui(r, r, 1); if (mpz_cmp_ui(pub->g, 2) < 0 || mpz_cmp(pub->g, r) >= 0) { goto fail; } /* g^q == 1 mod p */ mpz_powm(r, pub->g, pub->q, pub->p); if (mpz_cmp_ui(r, 1) != 0) { goto fail; } /* repeat g generation */ ret = _dsa_generate_dss_g(&pub2, domain_seed_size, domain_seed, NULL, NULL, index); if (ret == 0) { goto fail; } if (mpz_cmp(pub->g, pub2.g) != 0) { goto fail; } /* everything looks ok */ ret = 1; goto finish; fail: ret = 0; finish: dsa_params_clear(&pub2); mpz_clear(r); return ret; } int _dsa_validate_dss_pq(struct dsa_params *pub, struct dss_params_validation_seeds *cert) { int ret; unsigned p_bits, q_bits; struct dsa_params pub2; struct dss_params_validation_seeds cert2; mpz_t r, s; p_bits = mpz_sizeinbase(pub->p, 2); q_bits = mpz_sizeinbase(pub->q, 2); ret = _dsa_check_qp_sizes(q_bits, p_bits, 0); if (ret == 0) { return 0; } mpz_init(r); mpz_init(s); dsa_params_init(&pub2); nettle_mpz_set_str_256_u(s, cert->seed_length, cert->seed); /* firstseed < 2^(N-1) */ mpz_set_ui(r, 1); mpz_mul_2exp(r, r, q_bits - 1); if (mpz_cmp(s, r) < 0) { goto fail; } /* 2^N <= q */ mpz_set_ui(r, 1); mpz_mul_2exp(r, r, q_bits); if (mpz_cmp(r, pub->q) <= 0) { goto fail; } /* 2^L <= p */ mpz_set_ui(r, 1); mpz_mul_2exp(r, r, p_bits); if (mpz_cmp(r, pub->p) <= 0) { goto fail; } /* p-1 mod q != 0 */ mpz_set(r, pub->p); mpz_sub_ui(r, r, 1); mpz_mod(r, r, pub->q); if (mpz_cmp_ui(r, 0) != 0) { goto fail; } /* replay the construction */ ret = _dsa_generate_dss_pq(&pub2, &cert2, cert->seed_length, cert->seed, NULL, NULL, p_bits, q_bits); if (ret == 0) { goto fail; } if ((cert->pseed_length > 0 && cert->pseed_length != cert2.pseed_length) || (cert->qseed_length > 0 && cert->qseed_length != cert2.qseed_length) || (cert->pgen_counter > 0 && cert->pgen_counter != cert2.pgen_counter) || (cert->qgen_counter > 0 && cert->qgen_counter != cert2.qgen_counter) || (cert->qseed_length > 0 && memcmp(cert->qseed, cert2.qseed, cert2.qseed_length) != 0) || (cert->pseed_length > 0 && memcmp(cert->pseed, cert2.pseed, cert2.pseed_length) != 0)) { goto fail; } if (mpz_cmp(pub->q, pub2.q) != 0) { goto fail; } if (mpz_cmp(pub->p, pub2.p) != 0) { goto fail; } if (mpz_sizeinbase(s, 2) < q_bits - 1) { goto fail; } ret = 1; goto finish; fail: ret = 0; finish: dsa_params_clear(&pub2); mpz_clear(r); mpz_clear(s); return ret; }