diff options
author | Adam Langley <agl@chromium.org> | 2014-06-20 23:00:00 +0400 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2014-06-21 00:17:32 +0400 |
commit | 95c29f3cd1f6c08c6c0927868683392eea727ccb (patch) | |
tree | 012767320ced9abca61472a4daa4c4a56b7ebe2b /crypto/dsa |
Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).
(This change contains substantial changes from the original and
effectively starts a new history.)
Diffstat (limited to 'crypto/dsa')
-rw-r--r-- | crypto/dsa/CMakeLists.txt | 20 | ||||
-rw-r--r-- | crypto/dsa/dsa.c | 334 | ||||
-rw-r--r-- | crypto/dsa/dsa.h | 359 | ||||
-rw-r--r-- | crypto/dsa/dsa_asn1.c | 148 | ||||
-rw-r--r-- | crypto/dsa/dsa_error.c | 30 | ||||
-rw-r--r-- | crypto/dsa/dsa_impl.c | 723 | ||||
-rw-r--r-- | crypto/dsa/dsa_test.c | 214 | ||||
-rw-r--r-- | crypto/dsa/internal.h | 78 |
8 files changed, 1906 insertions, 0 deletions
diff --git a/crypto/dsa/CMakeLists.txt b/crypto/dsa/CMakeLists.txt new file mode 100644 index 00000000..6dfb2a6d --- /dev/null +++ b/crypto/dsa/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories(. .. ../../include) + +add_library( + dsa + + OBJECT + + dsa.c + dsa_impl.c + dsa_asn1.c + dsa_error.c +) + +add_executable( + dsa_test + + dsa_test.c +) + +target_link_libraries(dsa_test crypto) diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c new file mode 100644 index 00000000..4ae6876b --- /dev/null +++ b/crypto/dsa/dsa.c @@ -0,0 +1,334 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch <schoch@sheba.arc.nasa.gov>. */ + +#include <openssl/dsa.h> + +#include <openssl/asn1.h> +#include <openssl/engine.h> +#include <openssl/err.h> +#include <openssl/ex_data.h> +#include <openssl/mem.h> + +#include "internal.h" + +extern const DSA_METHOD DSA_default_method; + +DSA *DSA_new(void) { return DSA_new_method(NULL); } + +DSA *DSA_new_method(const ENGINE *engine) { + DSA *dsa = (DSA *)OPENSSL_malloc(sizeof(DSA)); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(DSA, DSA_new_method, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(dsa, 0, sizeof(DSA)); + + if (engine) { + dsa->meth = ENGINE_get_DSA_method(engine); + } + + if (dsa->meth == NULL) { + dsa->meth = (DSA_METHOD*) &DSA_default_method; + } + METHOD_ref(dsa->meth); + + dsa->write_params = 1; + dsa->references = 1; + + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data)) { + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + if (dsa->meth->init && !dsa->meth->init(dsa)) { + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data); + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + return dsa; +} + +void DSA_free(DSA *dsa) { + if (dsa == NULL) { + return; + } + + if (CRYPTO_add(&dsa->references, -1, CRYPTO_LOCK_DSA) > 0) { + return; + } + + if (dsa->meth->finish) { + dsa->meth->finish(dsa); + } + METHOD_unref(dsa->meth); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data); + + if (dsa->p != NULL) + BN_clear_free(dsa->p); + if (dsa->q != NULL) + BN_clear_free(dsa->q); + if (dsa->g != NULL) + BN_clear_free(dsa->g); + if (dsa->pub_key != NULL) + BN_clear_free(dsa->pub_key); + if (dsa->priv_key != NULL) + BN_clear_free(dsa->priv_key); + if (dsa->kinv != NULL) + BN_clear_free(dsa->kinv); + if (dsa->r != NULL) + BN_clear_free(dsa->r); + OPENSSL_free(dsa); +} + +int DSA_up_ref(DSA *dsa) { + CRYPTO_add(&dsa->references, 1, CRYPTO_LOCK_DSA); + return 1; +} + +int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *out_counter, + unsigned long *out_h, BN_GENCB *cb) { + if (dsa->meth->generate_parameters) { + return dsa->meth->generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); + } + return DSA_default_method.generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); +} + +int DSA_generate_key(DSA *dsa) { + if (dsa->meth->keygen) { + return dsa->meth->keygen(dsa); + } + return DSA_default_method.keygen(dsa); +} + +DSA_SIG *DSA_SIG_new(void) { + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + return NULL; + } + sig->r = NULL; + sig->s = NULL; + return sig; +} + +void DSA_SIG_free(DSA_SIG *sig) { + if (!sig) { + return; + } + + if (sig->r) { + BN_free(sig->r); + } + if (sig->s) { + BN_free(sig->s); + } + OPENSSL_free(sig); +} + +DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + if (dsa->meth->sign) { + return dsa->meth->sign(digest, digest_len, dsa); + } + return DSA_default_method.sign(digest, digest_len, dsa); +} + +int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig, + const DSA *dsa) { + int valid, ret; + + if (dsa->meth->verify) { + ret = dsa->meth->verify(&valid, digest, digest_len, sig, dsa); + } else { + ret = DSA_default_method.verify(&valid, digest, digest_len, sig, dsa); + } + + if (!ret) { + return -1; + } else if (!valid) { + return 0; + } + return 1; +} + +int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, const DSA *dsa) { + if (dsa->meth->verify) { + return dsa->meth->verify(out_valid, digest, digest_len, sig, dsa); + } + + return DSA_default_method.verify(out_valid, digest, digest_len, sig, dsa); +} + +int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) { + DSA_SIG *s; + + s = DSA_do_sign(digest, digest_len, dsa); + if (s == NULL) { + *out_siglen = 0; + return 0; + } + + *out_siglen = i2d_DSA_SIG(s, &out_sig); + DSA_SIG_free(s); + return 1; +} + +int DSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, const DSA *dsa) { + DSA_SIG *s = NULL; + int ret = -1, valid; + + s = DSA_SIG_new(); + if (s == NULL) { + goto err; + } + + if (d2i_DSA_SIG(&s, &sig, sig_len) == NULL) { + goto err; + } + + if (!DSA_do_check_signature(&valid, digest, digest_len, s, dsa)) { + goto err; + } + + ret = valid; + +err: + if (s) { + DSA_SIG_free(s); + } + return ret; +} + +int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, size_t sig_len, + const DSA *dsa) { + DSA_SIG *s = NULL; + int ret = 0; + + s = DSA_SIG_new(); + if (s == NULL) { + goto err; + } + + if (d2i_DSA_SIG(&s, &sig, sig_len) == NULL) { + goto err; + } + + ret = DSA_do_check_signature(out_valid, digest, digest_len, s, dsa); + +err: + if (s) { + DSA_SIG_free(s); + } + return ret; +} + +int DSA_size(const DSA *dsa) { + int ret, i; + ASN1_INTEGER bs; + unsigned char buf[4]; /* 4 bytes looks really small. + However, i2d_ASN1_INTEGER() will not look + beyond the first byte, as long as the second + parameter is NULL. */ + + i = BN_num_bits(dsa->q); + bs.length = (i + 7) / 8; + bs.data = buf; + bs.type = V_ASN1_INTEGER; + /* If the top bit is set the asn1 encoding is 1 larger. */ + buf[0] = 0xff; + + i = i2d_ASN1_INTEGER(&bs, NULL); + i += i; /* r and s */ + ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE); + return ret; +} + +int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, + BIGNUM **out_r) { + if (dsa->meth->sign_setup) { + return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r); + } + + return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r); +} + +int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_DSA, argl, argp, new_func, + dup_func, free_func); +} + +int DSA_set_ex_data(DSA *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *DSA_get_ex_data(const DSA *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} diff --git a/crypto/dsa/dsa.h b/crypto/dsa/dsa.h new file mode 100644 index 00000000..857edc0a --- /dev/null +++ b/crypto/dsa/dsa.h @@ -0,0 +1,359 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch <schoch@sheba.arc.nasa.gov>. */ + +#ifndef OPENSSL_HEADER_DSA_H +#define OPENSSL_HEADER_DSA_H + +#include <openssl/base.h> + +#include <openssl/engine.h> +#include <openssl/ex_data.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DSA contains functions for signing and verifing with the Digital Signature + * Algorithm. */ + + +/* Allocation and destruction. */ + +/* DSA_new returns a new, empty DSA object or NULL on error. */ +DSA *DSA_new(void); + +/* DSA_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */ +DSA *DSA_new_method(const ENGINE *engine); + +/* DSA_free decrements the reference count of |dsa| and frees it if the + * reference count drops to zero. */ +void DSA_free(DSA *dsa); + +/* DSA_up_ref increments the reference count of |dsa|. */ +int DSA_up_ref(DSA *dsa); + + +/* Parameter generation. */ + +/* DSA_generate_parameters_ex generates a set of DSA parameters by following + * the procedure given in FIPS 186-4, appendix A. + * (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) + * + * The larger prime will have a length of |bits| (e.g. 2048). The |seed| value + * allows others to generate and verify the same parameters and should be + * random input which is kept for reference. If |out_counter| or |out_h| are + * not NULL then the counter and h value used in the generation are written to + * them. + * + * The |cb| argument is passed to |BN_generate_prime_ex| and is thus called + * during the generation process in order to indicate progress. See the + * comments for that function for details. In addition to the calls made by + * |BN_generate_prime_ex|, |DSA_generate_parameters_ex| will call it with + * |event| equal to 2 and 3 at different stages of the process. + * + * It returns one on success and zero otherwise. */ +int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed, + size_t seed_len, int *out_counter, + unsigned long *out_h, BN_GENCB *cb); + +/* DSAparams_dup returns a freshly allocated |DSA| that contains a copy of the + * parameters from |dsa|. It returns NULL on error. */ +DSA *DSAparams_dup(const DSA *dsa); + + +/* Key generation. */ + +/* DSA_generate_key generates a public/private key pair in |dsa|, which must + * already have parameters setup. It returns one on success and zero on + * error. */ +int DSA_generate_key(DSA *dsa); + + +/* Signatures. */ + +/* DSA_SIG contains a DSA signature as a pair of integers. */ +typedef struct DSA_SIG_st { + BIGNUM *r, *s; +} DSA_SIG; + +/* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error. + * Both |r| and |s| in the signature will be NULL. */ +DSA_SIG *DSA_SIG_new(void); + +/* DSA_SIG_free frees the contents of |sig| and then frees |sig| itself. */ +void DSA_SIG_free(DSA_SIG *sig); + +/* DSA_do_sign returns a signature of the hash in |digest| by the key in |dsa| + * and returns an allocated, DSA_SIG structure, or NULL on error. */ +DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa); + +/* DSA_do_verify verifies that |sig| is a valid signature, by the public key in + * |dsa|, of the hash in |digest|. It returns one if so, zero if invalid and -1 + * on error. + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig, + const DSA *dsa); + +/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid signature, by the public key in |dsa| of the hash in |digest| + * and, if so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, const DSA *dsa); + + +/* ASN.1 signatures. + * + * These functions also perform DSA signature operations, but deal with ASN.1 + * encoded signatures as opposed to raw |BIGNUM|s. If you don't know what + * encoding a DSA signature is in, it's probably ASN.1. */ + +/* DSA_sign signs |digest| with the key in |dsa| and writes the resulting + * signature, in ASN.1 form, to |out_sig| and the length of the signature to + * |*out_siglen|. There must be, at least, |DSA_size(dsa)| bytes of space in + * |out_sig|. It returns one on success and zero otherwise. + * + * (The |type| argument is ignored.) */ +int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa); + +/* DSA_verify verifies that |sig| is a valid, ASN.1 signature, by the public + * key in |dsa|, of the hash in |digest|. It returns one if so, zero if invalid + * and -1 on error. + * + * (The |type| argument is ignored.) + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +int DSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, const DSA *dsa); + +/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid, ASN.1 signature, by the public key in |dsa|, of the hash in + * |digest|. If so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, size_t sig_len, + const DSA *dsa); + +/* DSA_size returns the size, in bytes, of an ASN.1 encoded, DSA signature + * generated by |dsa|. Parameters must already have been setup in |dsa|. */ +int DSA_size(const DSA *dsa); + + +/* ASN.1 encoding. */ + +/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at + * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is + * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is + * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated. + * On successful exit, |*inp| is advanced past the DER structure. It returns + * the result or NULL on error. */ +DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, long len); + +/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or not, + * or a negative value on error. */ +int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); + +/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +int i2d_DSAPublicKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |DSA| is allocated. On successful + * exit, |*inp| is advanced past the DER structure. It returns the result or + * NULL on error. */ +DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +int i2d_DSAparams(const DSA *in, unsigned char **outp); + + +/* Precomputation. */ + +/* DSA_sign_setup precomputes the message independent part of the DSA signature + * and writes them to |*out_kinv| and |*out_r|. Returns one on success, zero on + * error. + * + * TODO(fork): decide what to do with this. Since making DSA* opaque there's no + * way for the user to install them. Also, it forces the DSA* not to be const + * when passing to the signing function. */ +int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, + BIGNUM **out_r); + + +/* ex_data functions. + * + * These functions are wrappers. See |ex_data.h| for details. */ + +int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int DSA_set_ex_data(DSA *d, int idx, void *arg); +void *DSA_get_ex_data(const DSA *d, int idx); + + +struct dsa_method { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(DSA *dsa); + int (*finish)(DSA *dsa); + + DSA_SIG *(*sign)(const uint8_t *digest, size_t digest_len, DSA *dsa); + + int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp); + + int (*verify)(int *out_valid, const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + + /* generate_parameters, if non-NULL, is used to generate DSA parameters. */ + int (*generate_parameters)(DSA *dsa, unsigned bits, const uint8_t *seed, + size_t seed_len, int *counter_ret, + unsigned long *h_ret, BN_GENCB *cb); + + /* keygen, if non-NULL, is used to generate DSA keys. */ + int (*keygen)(DSA *dsa); +}; + +struct dsa_st { + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; /* == 20 */ + BIGNUM *g; + + BIGNUM *pub_key; /* y public key */ + BIGNUM *priv_key; /* x private key */ + + BIGNUM *kinv; /* Signing pre-calc */ + BIGNUM *r; /* Signing pre-calc */ + + int flags; + /* Normally used to cache montgomery values */ + BN_MONT_CTX *method_mont_p; + int references; + CRYPTO_EX_DATA ex_data; + DSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DSA_F_sign 100 +#define DSA_F_verify 101 +#define DSA_F_dsa_sig_cb 102 +#define DSA_F_DSA_new_method 103 +#define DSA_F_sign_setup 104 +#define DSA_R_NEED_NEW_SETUP_VALUES 100 +#define DSA_R_BAD_Q_VALUE 101 +#define DSA_R_MODULUS_TOO_LARGE 102 +#define DSA_R_MISSING_PARAMETERS 103 + +#endif /* OPENSSL_HEADER_DSA_H */ diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c new file mode 100644 index 00000000..72b2cc61 --- /dev/null +++ b/crypto/dsa/dsa_asn1.c @@ -0,0 +1,148 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. */ +/* ==================================================================== + * Copyright (c) 2000-2005 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 <openssl/dsa.h> + +#include <openssl/asn1.h> +#include <openssl/asn1t.h> +#include <openssl/err.h> +#include <openssl/mem.h> + +#include "internal.h" + + +static int dsa_sig_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + if (operation != ASN1_OP_NEW_PRE) { + return 1; + } + + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + OPENSSL_PUT_ERROR(DSA, dsa_sig_cb, ERR_R_MALLOC_FAILURE); + return 0; + } + + memset(sig, 0, sizeof(DSA_SIG)); + *pval = (ASN1_VALUE *)sig; + return 2; +} + +ASN1_SEQUENCE_cb(DSA_SIG, dsa_sig_cb) = { + ASN1_SIMPLE(DSA_SIG, r, CBIGNUM), + ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)} ASN1_SEQUENCE_END_cb(DSA_SIG, DSA_SIG); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG); + + +static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + switch (operation) { + case ASN1_OP_NEW_PRE: + *pval = (ASN1_VALUE *)DSA_new(); + if (*pval) { + return 2; + } + return 0; + + case ASN1_OP_FREE_PRE: + DSA_free((DSA *)*pval); + *pval = NULL; + return 2; + + default: + return 1; + } +} + +ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = { + ASN1_SIMPLE(DSA, version, LONG), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, priv_key, BIGNUM)} ASN1_SEQUENCE_END_cb(DSA, + DSAPrivateKey); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey); + +ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = { + ASN1_SIMPLE(DSA, p, BIGNUM), ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), } ASN1_SEQUENCE_END_cb(DSA, DSAparams); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams); + + +/* DSA public key is a bit trickier... its effectively a CHOICE type decided by + * a field called write_params which can either write out just the public key + * as an INTEGER or the parameters and public key in a SEQUENCE. */ + +ASN1_SEQUENCE(dsa_pub_internal) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM) +} ASN1_SEQUENCE_END_name(DSA, dsa_pub_internal); + +ASN1_CHOICE_cb(DSAPublicKey, dsa_cb) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_EX_COMBINE(0, 0, dsa_pub_internal) +} ASN1_CHOICE_END_cb(DSA, DSAPublicKey, write_params); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey); + +DSA *DSAparams_dup(const DSA *dsa) { + return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa); +} diff --git a/crypto/dsa/dsa_error.c b/crypto/dsa/dsa_error.c new file mode 100644 index 00000000..b6e08aef --- /dev/null +++ b/crypto/dsa/dsa_error.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/err.h> + +#include "dsa.h" + +const ERR_STRING_DATA DSA_error_string_data[] = { + {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_new_method, 0), "DSA_new_method"}, + {ERR_PACK(ERR_LIB_DSA, DSA_F_dsa_sig_cb, 0), "dsa_sig_cb"}, + {ERR_PACK(ERR_LIB_DSA, DSA_F_sign, 0), "sign"}, + {ERR_PACK(ERR_LIB_DSA, DSA_F_sign_setup, 0), "sign_setup"}, + {ERR_PACK(ERR_LIB_DSA, DSA_F_verify, 0), "verify"}, + {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_BAD_Q_VALUE), "BAD_Q_VALUE"}, + {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"}, + {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MODULUS_TOO_LARGE), "MODULUS_TOO_LARGE"}, + {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NEED_NEW_SETUP_VALUES), "NEED_NEW_SETUP_VALUES"}, + {0, NULL}, +}; diff --git a/crypto/dsa/dsa_impl.c b/crypto/dsa/dsa_impl.c new file mode 100644 index 00000000..dacc742a --- /dev/null +++ b/crypto/dsa/dsa_impl.c @@ -0,0 +1,723 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch <schoch@sheba.arc.nasa.gov>. */ + +#include <openssl/dsa.h> + +#include <openssl/bn.h> +#include <openssl/digest.h> +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/sha.h> + +#include "internal.h" + +#define OPENSSL_DSA_MAX_MODULUS_BITS 10000 + +/* Primality test according to FIPS PUB 186[-1], Appendix 2.1: 50 rounds of + * Rabin-Miller */ +#define DSS_prime_checks 50 + +static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp) { + BN_CTX *ctx; + BIGNUM k, kq, *K, *kinv = NULL, *r = NULL; + int ret = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, sign_setup, DSA_R_MISSING_PARAMETERS); + return 0; + } + + BN_init(&k); + BN_init(&kq); + + ctx = ctx_in; + if (ctx == NULL) { + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + r = BN_new(); + if (r == NULL) { + goto err; + } + + /* Get random k */ + do { + if (!BN_rand_range(&k, dsa->q)) { + goto err; + } + } while (BN_is_zero(&k)); + + BN_set_flags(&k, BN_FLG_CONSTTIME); + + if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + CRYPTO_LOCK_DSA, dsa->p, ctx)) { + goto err; + } + + /* Compute r = (g^k mod p) mod q */ + if (!BN_copy(&kq, &k)) + goto err; + + /* We do not want timing information to leak the length of k, + * so we compute g^k using an equivalent exponent of fixed length. + * + * (This is a kludge that we need because the BN_mod_exp_mont() + * does not let us specify the desired timing behaviour.) */ + + if (!BN_add(&kq, &kq, dsa->q)) + goto err; + if (BN_num_bits(&kq) <= BN_num_bits(dsa->q)) { + if (!BN_add(&kq, &kq, dsa->q)) + goto err; + } + + K = &kq; + + if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) { + goto err; + } + if (!BN_mod(r, r, dsa->q, ctx)) { + goto err; + } + + /* Compute part of 's = inv(k) (m + xr) mod q' */ + kinv = BN_mod_inverse(NULL, &k, dsa->q, ctx); + if (kinv == NULL) { + goto err; + } + + if (*kinvp != NULL) { + BN_clear_free(*kinvp); + } + *kinvp = kinv; + kinv = NULL; + if (*rp != NULL) { + BN_clear_free(*rp); + } + *rp = r; + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, sign_setup, ERR_R_BN_LIB); + if (r != NULL) { + BN_clear_free(r); + } + } + + if (ctx_in == NULL) { + BN_CTX_free(ctx); + } + BN_clear_free(&k); + BN_clear_free(&kq); + return ret; +} + +static DSA_SIG *sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + BIGNUM *kinv = NULL, *r = NULL, *s = NULL; + BIGNUM m; + BIGNUM xr; + BN_CTX *ctx = NULL; + int reason = ERR_R_BN_LIB; + DSA_SIG *ret = NULL; + int noredo = 0; + + BN_init(&m); + BN_init(&xr); + + if (!dsa->p || !dsa->q || !dsa->g) { + reason = DSA_R_MISSING_PARAMETERS; + goto err; + } + + s = BN_new(); + if (s == NULL) { + goto err; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + +redo: + if (dsa->kinv == NULL || dsa->r == NULL) { + if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) { + goto err; + } + } else { + kinv = dsa->kinv; + dsa->kinv = NULL; + r = dsa->r; + dsa->r = NULL; + noredo = 1; + } + + if (digest_len > BN_num_bytes(dsa->q)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = BN_num_bytes(dsa->q); + } + + if (BN_bin2bn(digest, digest_len, &m) == NULL) { + goto err; + } + + /* Compute s = inv(k) (m + xr) mod q */ + if (!BN_mod_mul(&xr, dsa->priv_key, r, dsa->q, ctx)) { + goto err; /* s = xr */ + } + if (!BN_add(s, &xr, &m)) { + goto err; /* s = m + xr */ + } + if (BN_cmp(s, dsa->q) > 0) { + if (!BN_sub(s, s, dsa->q)) { + goto err; + } + } + if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) { + goto err; + } + + ret = DSA_SIG_new(); + if (ret == NULL) { + goto err; + } + /* Redo if r or s is zero as required by FIPS 186-3: this is + * very unlikely. */ + if (BN_is_zero(r) || BN_is_zero(s)) { + if (noredo) { + reason = DSA_R_NEED_NEW_SETUP_VALUES; + goto err; + } + goto redo; + } + ret->r = r; + ret->s = s; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, sign, reason); + BN_free(r); + BN_free(s); + } + if (ctx != NULL) { + BN_CTX_free(ctx); + } + BN_clear_free(&m); + BN_clear_free(&xr); + if (kinv != NULL) { + /* dsa->kinv is NULL now if we used it */ + BN_clear_free(kinv); + } + + return ret; +} + +static int verify(int *out_valid, const uint8_t *dgst, size_t digest_len, + DSA_SIG *sig, const DSA *dsa) { + BN_CTX *ctx; + BIGNUM u1, u2, t1; + BN_MONT_CTX *mont = NULL; + int ret = 0; + unsigned i; + + *out_valid = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, verify, DSA_R_MISSING_PARAMETERS); + return 0; + } + + i = BN_num_bits(dsa->q); + /* fips 186-3 allows only different sizes for q */ + if (i != 160 && i != 224 && i != 256) { + OPENSSL_PUT_ERROR(DSA, verify, DSA_R_BAD_Q_VALUE); + return 0; + } + + if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(DSA, verify, DSA_R_MODULUS_TOO_LARGE); + return 0; + } + + BN_init(&u1); + BN_init(&u2); + BN_init(&t1); + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + BN_ucmp(sig->r, dsa->q) >= 0) { + ret = 1; + goto err; + } + if (BN_is_zero(sig->s) || BN_is_negative(sig->s) || + BN_ucmp(sig->s, dsa->q) >= 0) { + ret = 1; + goto err; + } + + /* Calculate W = inv(S) mod Q + * save W in u2 */ + if (BN_mod_inverse(&u2, sig->s, dsa->q, ctx) == NULL) { + goto err; + } + + /* save M in u1 */ + if (digest_len > (i >> 3)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = (i >> 3); + } + + if (BN_bin2bn(dgst, digest_len, &u1) == NULL) { + goto err; + } + + /* u1 = M * w mod q */ + if (!BN_mod_mul(&u1, &u1, &u2, dsa->q, ctx)) { + goto err; + } + + /* u2 = r * w mod q */ + if (!BN_mod_mul(&u2, sig->r, &u2, dsa->q, ctx)) { + goto err; + } + + mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + CRYPTO_LOCK_DSA, dsa->p, ctx); + if (!mont) { + goto err; + } + + if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, mont)) { + goto err; + } + + /* BN_copy(&u1,&t1); */ + /* let u1 = u1 mod q */ + if (!BN_mod(&u1, &t1, dsa->q, ctx)) { + goto err; + } + + /* V is now in u1. If the signature is correct, it will be + * equal to R. */ + *out_valid = BN_ucmp(&u1, sig->r) == 0; + ret = 1; + +err: + if (ret != 1) { + OPENSSL_PUT_ERROR(DSA, verify, ERR_R_BN_LIB); + } + if (ctx != NULL) { + BN_CTX_free(ctx); + } + BN_free(&u1); + BN_free(&u2); + BN_free(&t1); + + return ret; +} + +static int keygen(DSA *dsa) { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL, *priv_key = NULL; + BIGNUM prk; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + priv_key = dsa->priv_key; + if (priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + } + + do { + if (!BN_rand_range(priv_key, dsa->q)) { + goto err; + } + } while (BN_is_zero(priv_key)); + + pub_key = dsa->pub_key; + if (pub_key == NULL) { + pub_key = BN_new(); + if (pub_key == NULL) { + goto err; + } + } + + BN_init(&prk); + BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME); + + if (!BN_mod_exp(pub_key, dsa->g, &prk, dsa->p, ctx)) { + goto err; + } + + dsa->priv_key = priv_key; + dsa->pub_key = pub_key; + ok = 1; + +err: + if (pub_key != NULL && dsa->pub_key == NULL) { + BN_free(pub_key); + } + if (priv_key != NULL && dsa->priv_key == NULL) { + BN_free(priv_key); + } + if (ctx != NULL) { + BN_CTX_free(ctx); + } + + return ok; +} + +static int paramgen(DSA *ret, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb) { + int ok = 0; + unsigned char seed[SHA256_DIGEST_LENGTH]; + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH]; + BIGNUM *r0, *W, *X, *c, *test; + BIGNUM *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + int k, n = 0, m = 0; + unsigned i; + int counter = 0; + int r = 0; + BN_CTX *ctx = NULL; + unsigned int h = 2; + unsigned qbits, qsize; + const EVP_MD *evpmd; + + if (bits >= 2048) { + qbits = 256; + evpmd = EVP_sha256(); + } else { + qbits = 160; + evpmd = EVP_sha1(); + } + qsize = qbits / 8; + + if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH && + qsize != SHA256_DIGEST_LENGTH) + /* invalid q size */ + return 0; + + if (bits < 512) + bits = 512; + + bits = (bits + 63) / 64 * 64; + + /* NB: seed_len == 0 is special case: copy generated seed to + * seed_in if it is not NULL. */ + if (seed_len && (seed_len < (size_t)qsize)) + seed_in = NULL; /* seed buffer too small -- ignore */ + if (seed_len > (size_t)qsize) + seed_len = qsize; /* App. 2.2 of FIPS PUB 186 allows larger SEED, + * but our internal buffers are restricted to 160 bits*/ + if (seed_in != NULL) + memcpy(seed, seed_in, seed_len); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + if ((mont = BN_MONT_CTX_new()) == NULL) + goto err; + + BN_CTX_start(ctx); + 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 (!BN_lshift(test, BN_value_one(), bits - 1)) + goto err; + + for (;;) { + for (;;) /* find q */ + { + int seed_is_random; + + /* step 1 */ + if (!BN_GENCB_call(cb, 0, m++)) + goto err; + + if (!seed_len) { + RAND_pseudo_bytes(seed, qsize); + seed_is_random = 1; + } else { + seed_is_random = 0; + seed_len = 0; /* use random seed if 'seed_in' turns out to be bad*/ + } + memcpy(buf, seed, qsize); + memcpy(buf2, seed, qsize); + /* precompute "SEED + 1" for step 7: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) + break; + } + + /* step 2 */ + if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL)) + goto err; + if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) + goto err; + for (i = 0; i < qsize; i++) + md[i] ^= buf2[i]; + + /* step 3 */ + md[0] |= 0x80; + md[qsize - 1] |= 0x01; + if (!BN_bin2bn(md, qsize, q)) + goto err; + + /* step 4 */ + r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb); + if (r > 0) + break; + if (r != 0) + goto err; + + /* do a callback call */ + /* step 5 */ + } + + if (!BN_GENCB_call(cb, 2, 0)) + goto err; + if (!BN_GENCB_call(cb, 3, 0)) + goto err; + + /* step 6 */ + counter = 0; + /* "offset = 2" */ + + n = (bits - 1) / 160; + + for (;;) { + if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) + goto err; + + /* step 7 */ + BN_zero(W); + /* now 'buf' contains "SEED + offset - 1" */ + for (k = 0; k <= n; k++) { + /* obtain "SEED + offset + k" by incrementing: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) + break; + } + + if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL)) + goto err; + + /* step 8 */ + if (!BN_bin2bn(md, qsize, r0)) + goto err; + if (!BN_lshift(r0, r0, (qsize << 3) * k)) + goto err; + if (!BN_add(W, W, r0)) + goto err; + } + + /* more of step 8 */ + if (!BN_mask_bits(W, bits - 1)) + goto err; + if (!BN_copy(X, W)) + goto err; + if (!BN_add(X, X, test)) + goto err; + + /* step 9 */ + if (!BN_lshift1(r0, q)) + goto err; + if (!BN_mod(c, X, r0, ctx)) + goto err; + if (!BN_sub(r0, c, BN_value_one())) + goto err; + if (!BN_sub(p, X, r0)) + goto err; + + /* step 10 */ + if (BN_cmp(p, test) >= 0) { + /* step 11 */ + r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb); + if (r > 0) + goto end; /* found it */ + if (r != 0) + goto err; + } + + /* step 13 */ + counter++; + /* "offset = offset + n + 1" */ + + /* step 14 */ + if (counter >= 4096) + break; + } + } +end: + if (!BN_GENCB_call(cb, 2, 1)) + goto err; + + /* 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 (!BN_MONT_CTX_set(mont, p, ctx)) + goto err; + + for (;;) { + /* 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; + h++; + } + + if (!BN_GENCB_call(cb, 3, 1)) + goto err; + + ok = 1; + +err: + if (ok) { + if (ret->p) + BN_free(ret->p); + if (ret->q) + BN_free(ret->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) { + ok = 0; + goto err; + } + if (counter_ret != NULL) + *counter_ret = counter; + if (h_ret != NULL) + *h_ret = h; + } + + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + if (mont != NULL) + BN_MONT_CTX_free(mont); + + return ok; +} + +static int finish(DSA *dsa) { + BN_MONT_CTX_free(dsa->method_mont_p); + dsa->method_mont_p = NULL; + return 1; +} + +const struct dsa_method DSA_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + + NULL /* init */, + finish /* finish */, + + sign, + sign_setup, + verify, + + paramgen, + keygen, +}; diff --git a/crypto/dsa/dsa_test.c b/crypto/dsa/dsa_test.c new file mode 100644 index 00000000..8841c129 --- /dev/null +++ b/crypto/dsa/dsa_test.c @@ -0,0 +1,214 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch <schoch@sheba.arc.nasa.gov>. */ + +#include <openssl/dsa.h> + +#include <openssl/bio.h> +#include <openssl/bn.h> + +#include "internal.h" + + +static int dsa_cb(int p, int n, BN_GENCB *arg); + +/* seed, out_p, out_q, out_g are taken from the updated Appendix 5 to + * FIPS PUB 186 and also appear in Appendix 5 to FIPS PIB 186-1 */ +static unsigned char seed[20] = {0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b, + 0xa8, 0xb6, 0x21, 0x1b, 0x40, 0x62, 0xba, + 0x32, 0x24, 0xe0, 0x42, 0x7d, 0xd3, }; + +static unsigned char out_p[] = { + 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, 0xaa, 0x3d, 0x25, 0x75, + 0x9b, 0xb0, 0x68, 0x69, 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, + 0x0c, 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, 0xe5, 0xd0, + 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, 0xaf, 0xc2, 0xe9, 0xad, 0xac, + 0x32, 0xab, 0x7a, 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, + 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, 0x91, }; + +static unsigned char out_q[] = {0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, + 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, + 0xf4, 0x8e, 0xda, 0xce, 0x91, 0x5f, }; + +static unsigned char out_g[] = { + 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, 0x13, 0x41, 0x31, 0x63, + 0xa5, 0x5b, 0x4c, 0xb5, 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, + 0xef, 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, 0x2e, 0x71, + 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, 0xbf, 0x58, 0xe5, 0xb7, 0x95, + 0x21, 0x92, 0x5c, 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, + 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, 0x02, }; + +static const uint8_t str1[]="12345678901234567890"; + +static BIO *bio_err = NULL; +static BIO *bio_out = NULL; + +int main(int argc, char **argv) { + BN_GENCB cb; + DSA *dsa = NULL; + int counter, ok = 0, i, j; + unsigned char buf[256]; + unsigned long h; + unsigned char sig[256]; + unsigned int siglen; + + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); + + BIO_printf(bio_out, "test generation of DSA parameters\n"); + + BN_GENCB_set(&cb, dsa_cb, bio_out); + dsa = DSA_new(); + if (dsa == NULL || + !DSA_generate_parameters_ex(dsa, 512, seed, 20, &counter, &h, &cb)) { + goto end; + } + + BIO_printf(bio_out, "seed\n"); + for (i = 0; i < 20; i += 4) { + BIO_printf(bio_out, "%02X%02X%02X%02X ", seed[i], seed[i + 1], seed[i + 2], + seed[i + 3]); + } + BIO_printf(bio_out, "\ncounter=%d h=%ld\n", counter, h); + + if (counter != 105) { + BIO_printf(bio_err, "counter should be 105\n"); + goto end; + } + if (h != 2) { + BIO_printf(bio_err, "h should be 2\n"); + goto end; + } + + i = BN_bn2bin(dsa->q, buf); + j = sizeof(out_q); + if (i != j || memcmp(buf, out_q, i) != 0) { + BIO_printf(bio_err, "q value is wrong\n"); + goto end; + } + + i = BN_bn2bin(dsa->p, buf); + j = sizeof(out_p); + if (i != j || memcmp(buf, out_p, i) != 0) { + BIO_printf(bio_err, "p value is wrong\n"); + goto end; + } + + i = BN_bn2bin(dsa->g, buf); + j = sizeof(out_g); + if (i != j || memcmp(buf, out_g, i) != 0) { + BIO_printf(bio_err, "g value is wrong\n"); + goto end; + } + + DSA_generate_key(dsa); + DSA_sign(0, str1, 20, sig, &siglen, dsa); + if (DSA_verify(0, str1, 20, sig, siglen, dsa) == 1) { + ok = 1; + } else { + BIO_printf(bio_err, "verification failure\n"); + } + +end: + if (!ok) { + BIO_print_errors(bio_err); + } + if (dsa != NULL) { + DSA_free(dsa); + } + + BIO_free(bio_err); + BIO_free(bio_out); + + if (ok) { + printf("PASS\n"); + } + + return ok == 1 ? 0 : 1; +} + +static int dsa_cb(int p, int n, BN_GENCB *arg) { + char c = '*'; + static int ok = 0, num = 0; + + switch (p) { + case 0: + c = '.'; + num++; + break; + case 1: + c = '+'; + break; + case 2: + c = '*'; + ok++; + break; + case 3: + c = '\n'; + } + + BIO_write(arg->arg, &c, 1); + (void)BIO_flush(arg->arg); + + if (!ok && p == 0 && num > 1) { + BIO_printf((BIO *)arg, "error in dsatest\n"); + return 0; + } + + return 1; +} diff --git a/crypto/dsa/internal.h b/crypto/dsa/internal.h new file mode 100644 index 00000000..ef991585 --- /dev/null +++ b/crypto/dsa/internal.h @@ -0,0 +1,78 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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 acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch <schoch@sheba.arc.nasa.gov>. */ + +#ifndef OPENSSL_HEADER_DSA_INTERNAL_H +#define OPENSSL_HEADER_DSA_INTERNAL_H + +#include <openssl/base.h> + +#include <openssl/bn.h> +#include <openssl/ex_data.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DSA_INTERNAL_H */ |