diff options
-rw-r--r-- | cipher/dsa.c | 15 | ||||
-rw-r--r-- | cipher/ecc.c | 101 | ||||
-rw-r--r-- | cipher/elgamal.c | 40 | ||||
-rw-r--r-- | cipher/pubkey.c | 487 | ||||
-rw-r--r-- | cipher/rsa.c | 62 | ||||
-rw-r--r-- | mpi/mpicoder.c | 58 | ||||
-rw-r--r-- | src/cipher-proto.h | 4 | ||||
-rw-r--r-- | src/cipher.h | 1 | ||||
-rw-r--r-- | src/mpi.h | 3 | ||||
-rw-r--r-- | tests/t-ed25519.c | 2 |
10 files changed, 298 insertions, 475 deletions
diff --git a/cipher/dsa.c b/cipher/dsa.c index ca9a4f68..13a4fc26 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -974,11 +974,12 @@ dsa_check_secret_key (int algo, gcry_mpi_t *skey) static gcry_err_code_t -dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, +dsa_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey, int flags, int hashalgo) { gcry_err_code_t rc; DSA_secret_key sk; + gcry_mpi_t r, s; (void)algo; (void)flags; @@ -995,9 +996,15 @@ dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, sk.g = skey[2]; sk.y = skey[3]; sk.x = skey[4]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); - rc = sign (resarr[0], resarr[1], data, &sk, flags, hashalgo); + r = mpi_alloc (mpi_get_nlimbs (sk.p)); + s = mpi_alloc (mpi_get_nlimbs (sk.p)); + rc = sign (r, s, data, &sk, flags, hashalgo); + if (!rc) + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(sig-val(dsa(r%M)(s%M)))", + r, s)); + mpi_free (r); + mpi_free (s); } return rc; } diff --git a/cipher/ecc.c b/cipher/ecc.c index 66cd342d..b7d62397 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -1375,11 +1375,12 @@ ecc_check_secret_key (int algo, gcry_mpi_t *skey) static gcry_err_code_t -ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, +ecc_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey, int flags, int hashalgo) { - gpg_err_code_t err; + gpg_err_code_t rc; ECC_secret_key sk; + gcry_mpi_t r, s; (void)algo; @@ -1397,16 +1398,17 @@ ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, sk.Q.x = NULL; sk.Q.y = NULL; sk.Q.z = NULL; - err = _gcry_ecc_os2ec (&sk.E.G, skey[3]); - if (err) + rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]); + if (rc) { point_free (&sk.E.G); - return err; + return rc; } sk.E.n = skey[4]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); + r = mpi_alloc (mpi_get_nlimbs (sk.E.p)); + s = mpi_alloc (mpi_get_nlimbs (sk.E.p)); + { const unsigned char *buf; unsigned int n; @@ -1415,35 +1417,42 @@ ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, buf = gcry_mpi_get_opaque (skey[6], &n); if (!buf) - err = GPG_ERR_INV_OBJ; + rc = GPG_ERR_INV_OBJ; else { n = (n + 7)/8; sk.d = NULL; - err = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL); - if (!err) + rc = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL); + if (!rc) { if ((flags & PUBKEY_FLAG_EDDSA)) - err = sign_eddsa (data, &sk, resarr[0], resarr[1], - hashalgo, skey[5]); + { + rc = sign_eddsa (data, &sk, r, s, hashalgo, skey[5]); + if (!rc) + rc = gcry_err_code (gcry_sexp_build + (r_result, NULL, + "(sig-val(eddsa(r%M)(s%M)))", r, s)); + } else - err = sign_ecdsa (data, &sk, resarr[0], resarr[1], - flags, hashalgo); + { + rc = sign_ecdsa (data, &sk, r, s, flags, hashalgo); + if (!rc) + rc = gcry_err_code (gcry_sexp_build + (r_result, NULL, + "(sig-val(ecdsa(r%M)(s%M)))", r, s)); + } gcry_mpi_release (sk.d); sk.d = NULL; } } } - if (err) - { - mpi_free (resarr[0]); - mpi_free (resarr[1]); - resarr[0] = NULL; /* Mark array as released. */ - } + + mpi_free (r); + mpi_free (s); point_free (&sk.E.G); if (sk.Q.x) point_free (&sk.Q); - return err; + return rc; } @@ -1544,9 +1553,9 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, * ecc_encrypt_raw description: * input: * data[0] : private scalar (k) - * output: - * result[0] : shared point (kdG) - * result[1] : generated ephemeral public key (kG) + * output: A new S-expression with the parameters: + * s : shared point (kdG) + * e : generated ephemeral public key (kG) * * ecc_decrypt_raw description: * input: @@ -1555,13 +1564,13 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, * result[0] : shared point (kdG) */ static gcry_err_code_t -ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k, +ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k, gcry_mpi_t *pkey, int flags) { + gpg_err_code_t rc; ECC_public_key pk; mpi_ec_t ctx; - gcry_mpi_t result[2]; - int err; + gcry_mpi_t s, e; (void)algo; (void)flags; @@ -1575,24 +1584,26 @@ ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k, pk.E.a = pkey[1]; pk.E.b = pkey[2]; point_init (&pk.E.G); - err = _gcry_ecc_os2ec (&pk.E.G, pkey[3]); - if (err) + rc = _gcry_ecc_os2ec (&pk.E.G, pkey[3]); + if (rc) { point_free (&pk.E.G); - return err; + return rc; } pk.E.n = pkey[4]; point_init (&pk.Q); - err = _gcry_ecc_os2ec (&pk.Q, pkey[5]); - if (err) + rc = _gcry_ecc_os2ec (&pk.Q, pkey[5]); + if (rc) { point_free (&pk.E.G); point_free (&pk.Q); - return err; + return rc; } ctx = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, pk.E.p, pk.E.a, pk.E.b); + s = mpi_alloc (mpi_get_nlimbs (pk.E.p)); + e = mpi_alloc (mpi_get_nlimbs (pk.E.p)); /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */ { @@ -1609,16 +1620,14 @@ ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k, if (_gcry_mpi_ec_get_affine (x, y, &R, ctx)) log_fatal ("ecdh: Failed to get affine coordinates for kdG\n"); - - result[0] = _gcry_ecc_ec2os (x, y, pk.E.p); + s = _gcry_ecc_ec2os (x, y, pk.E.p); /* R = kG */ _gcry_mpi_ec_mul_point (&R, k, &pk.E.G, ctx); if (_gcry_mpi_ec_get_affine (x, y, &R, ctx)) log_fatal ("ecdh: Failed to get affine coordinates for kG\n"); - - result[1] = _gcry_ecc_ec2os (x, y, pk.E.p); + e = _gcry_ecc_ec2os (x, y, pk.E.p); mpi_free (x); mpi_free (y); @@ -1630,18 +1639,13 @@ ecc_encrypt_raw (int algo, gcry_mpi_t *resarr, gcry_mpi_t k, point_free (&pk.E.G); point_free (&pk.Q); - if (!result[0] || !result[1]) - { - mpi_free (result[0]); - mpi_free (result[1]); - return GPG_ERR_ENOMEM; - } - - /* Success. */ - resarr[0] = result[0]; - resarr[1] = result[1]; + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(enc-val(ecdh(s%m)(e%m)))", + s, e)); + mpi_free (s); + mpi_free (e); - return 0; + return rc; } /* input: @@ -1991,6 +1995,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) static const char *ecdsa_names[] = { "ecdsa", + "eddsa", "ecc", NULL, }; diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 65448e0a..447d089d 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -705,27 +705,33 @@ elg_check_secret_key (int algo, gcry_mpi_t *skey) static gcry_err_code_t -elg_encrypt (int algo, gcry_mpi_t *resarr, +elg_encrypt (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *pkey, int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; ELG_public_key pk; + gcry_mpi_t a, b; (void)algo; (void)flags; if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2])) - err = GPG_ERR_BAD_MPI; + rc = GPG_ERR_BAD_MPI; else { pk.p = pkey[0]; pk.g = pkey[1]; pk.y = pkey[2]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.p)); - do_encrypt (resarr[0], resarr[1], data, &pk); + a = mpi_alloc (mpi_get_nlimbs (pk.p)); + b = mpi_alloc (mpi_get_nlimbs (pk.p)); + do_encrypt (a, b, data, &pk); + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(enc-val(elg(a%m)(b%m)))", + a, b)); + mpi_free (a); + mpi_free (b); } - return err; + return rc; } @@ -756,11 +762,12 @@ elg_decrypt (int algo, gcry_mpi_t *result, static gcry_err_code_t -elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, +elg_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey, int flags, int hashalgo) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; ELG_secret_key sk; + gcry_mpi_t r, s; (void)algo; (void)flags; @@ -771,19 +778,24 @@ elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, if ((! data) || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - err = GPG_ERR_BAD_MPI; + rc = GPG_ERR_BAD_MPI; else { sk.p = skey[0]; sk.g = skey[1]; sk.y = skey[2]; sk.x = skey[3]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); - sign (resarr[0], resarr[1], data, &sk); + r = mpi_alloc (mpi_get_nlimbs (sk.p)); + s = mpi_alloc (mpi_get_nlimbs (sk.p)); + sign (r, s, data, &sk); + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(sig-val(elg(r%M)(s%M)))", + r, s)); + mpi_free (r); + mpi_free (s); } - return err; + return rc; } diff --git a/cipher/pubkey.c b/cipher/pubkey.c index c7557299..dc56cc31 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -33,17 +33,6 @@ #include "pubkey-internal.h" -static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, - int flags); -static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, - gcry_mpi_t hash, gcry_mpi_t *skey, - struct pk_encoding_ctx *ctx); -static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, - gcry_mpi_t *data, gcry_mpi_t *pkey, - struct pk_encoding_ctx *ctx); - - /* This is the list of the public-key algorithms included in Libgcrypt. */ static gcry_pk_spec_t *pubkey_list[] = @@ -308,161 +297,6 @@ pubkey_check_secret_key (int algo, gcry_mpi_t *skey) } -/**************** - * This is the interface to the public key encryption. Encrypt DATA - * with PKEY and put it into RESARR which should be an array of MPIs - * of size PUBKEY_MAX_NENC (or less if the algorithm allows this - - * check with pubkey_get_nenc() ) - */ -static gcry_err_code_t -pubkey_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - gcry_err_code_t rc; - gcry_pk_spec_t *spec; - int i; - - /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as - an extra failsafe protection we explicitly test for fips mode - here. */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_encrypt: algo=%d\n", algo); - for(i = 0; i < pubkey_get_npkey (algo); i++) - log_mpidump (" pkey", pkey[i]); - log_mpidump (" data", data); - } - - spec = spec_from_algo (algo); - if (spec && spec->encrypt) - rc = spec->encrypt (algo, resarr, data, pkey, flags); - else if (spec) - rc = GPG_ERR_NOT_IMPLEMENTED; - else - rc = GPG_ERR_PUBKEY_ALGO; - - if (!rc && DBG_CIPHER && !fips_mode ()) - { - for(i = 0; i < pubkey_get_nenc (algo); i++) - log_mpidump(" encr", resarr[i] ); - } - return rc; -} - - -/**************** - * This is the interface to the public key decryption. - * ALGO gives the algorithm to use and this implicitly determines - * the size of the arrays. - * result is a pointer to a mpi variable which will receive a - * newly allocated mpi or NULL in case of an error. - */ -static gcry_err_code_t -pubkey_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - gcry_err_code_t rc; - gcry_pk_spec_t *spec; - int i; - - *result = NULL; /* So the caller can always do a mpi_free. */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_decrypt: algo=%d\n", algo); - for(i = 0; i < pubkey_get_nskey (algo); i++) - log_mpidump (" skey", skey[i]); - for(i = 0; i < pubkey_get_nenc (algo); i++) - log_mpidump (" data", data[i]); - } - - spec = spec_from_algo (algo); - if (spec && spec->decrypt) - rc = spec->decrypt (algo, result, data, skey, flags); - else if (spec) - rc = GPG_ERR_NOT_IMPLEMENTED; - else - rc = GPG_ERR_PUBKEY_ALGO; - - if (!rc && DBG_CIPHER && !fips_mode ()) - log_mpidump (" plain", *result); - - return rc; -} - - -/**************** - * This is the interface to the public key signing. - * Sign data with skey and put the result into resarr which - * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the - * algorithm allows this - check with pubkey_get_nsig() ) - */ -static gcry_err_code_t -pubkey_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey, struct pk_encoding_ctx *ctx) -{ - gcry_err_code_t rc; - gcry_pk_spec_t *spec; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_sign: algo=%d\n", algo); - for(i = 0; i < pubkey_get_nskey (algo); i++) - log_mpidump (" skey", skey[i]); - log_mpidump(" data", data ); - } - - spec = spec_from_algo (algo); - if (spec && spec->sign) - rc = spec->sign (algo, resarr, data, skey, ctx->flags, ctx->hash_algo); - else if (spec) - rc = GPG_ERR_NOT_IMPLEMENTED; - else - rc = GPG_ERR_PUBKEY_ALGO; - - if (!rc && DBG_CIPHER && !fips_mode ()) - for (i = 0; i < pubkey_get_nsig (algo); i++) - log_mpidump (" sig", resarr[i]); - - return rc; -} - - -/**************** - * Verify a public key signature. - * Return 0 if the signature is good - */ -static gcry_err_code_t -pubkey_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, struct pk_encoding_ctx *ctx) -{ - gcry_err_code_t rc; - gcry_pk_spec_t *spec; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_verify: algo=%d\n", algo); - for (i = 0; i < pubkey_get_npkey (algo); i++) - log_mpidump (" pkey", pkey[i]); - for (i = 0; i < pubkey_get_nsig (algo); i++) - log_mpidump (" sig", data[i]); - log_mpidump (" hash", hash); - } - - spec = spec_from_algo (algo); - if (spec && spec->verify) - rc = spec->verify (algo, hash, data, pkey, - ctx->verify_cmp, ctx, ctx->flags, ctx->hash_algo); - else if (spec) - rc = GPG_ERR_NOT_IMPLEMENTED; - else - rc = GPG_ERR_PUBKEY_ALGO; - - return rc; -} - - /* Turn VALUE into an octet string and store it in an allocated buffer at R_FRAME or - if R_RAME is NULL - copy it into the caller provided buffer SPACE; either SPACE or R_FRAME may be used. If @@ -474,50 +308,7 @@ static gpg_err_code_t octet_string_from_mpi (unsigned char **r_frame, void *space, gcry_mpi_t value, size_t nbytes) { - gpg_err_code_t rc; - size_t nframe, noff, n; - unsigned char *frame; - - if (!r_frame == !space) - return GPG_ERR_INV_ARG; /* Only one may be used. */ - - if (r_frame) - *r_frame = NULL; - - rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, - NULL, 0, &nframe, value)); - if (rc) - return rc; - if (nframe > nbytes) - return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */ - - noff = (nframe < nbytes)? nbytes - nframe : 0; - n = nframe + noff; - if (space) - frame = space; - else - { - frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n); - if (!frame) - { - rc = gpg_err_code_from_syserror (); - return rc; - } - } - if (noff) - memset (frame, 0, noff); - nframe += noff; - rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, - frame+noff, nframe-noff, NULL, value)); - if (rc) - { - gcry_free (frame); - return rc; - } - - if (r_frame) - *r_frame = frame; - return 0; + return _gcry_mpi_to_octet_string (r_frame, space, value, nbytes); } @@ -2210,13 +2001,22 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, } else if ( n == 5 && !memcmp (s, "pkcs1", 5) && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_PKCS1; + { + ctx->encoding = PUBKEY_ENC_PKCS1; + parsed_flags |= PUBKEY_FLAG_FIXEDLEN; + } else if ( n == 4 && !memcmp (s, "oaep", 4) && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_OAEP; + { + ctx->encoding = PUBKEY_ENC_OAEP; + parsed_flags |= PUBKEY_FLAG_FIXEDLEN; + } else if ( n == 3 && !memcmp (s, "pss", 3) && ctx->encoding == PUBKEY_ENC_UNKNOWN) - ctx->encoding = PUBKEY_ENC_PSS; + { + ctx->encoding = PUBKEY_ENC_PSS; + parsed_flags |= PUBKEY_FLAG_FIXEDLEN; + } else if (n == 11 && ! memcmp (s, "no-blinding", 11)) parsed_flags |= PUBKEY_FLAG_NO_BLINDING; else @@ -2646,11 +2446,12 @@ init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op, gcry_error_t gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) { - gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL; - const char *algo_name, *algo_elems; - struct pk_encoding_ctx ctx; gcry_err_code_t rc; + gcry_mpi_t *pkey = NULL; + gcry_mpi_t data = NULL; + struct pk_encoding_ctx ctx; gcry_pk_spec_t *spec = NULL; + int i; *r_ciph = NULL; @@ -2661,116 +2462,43 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) gcry_assert (spec); - /* If aliases for the algorithm name exists, take the first one - instead of the regular name to adhere to SPKI conventions. We - assume that the first alias name is the lowercase version of the - regular one. This change is required for compatibility with - 1.1.12 generated S-expressions. */ - algo_name = spec->aliases? *spec->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = spec->name; - - algo_elems = spec->elements_enc; - /* Get the stuff we want to encrypt. */ init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey)); rc = sexp_data_to_mpi (s_data, &data, &ctx); if (rc) goto leave; - /* Now we can encrypt DATA to CIPH. */ - ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph)); - if (!ciph) + /* In fips mode DBG_CIPHER will never evaluate to true but as an + extra failsafe protection we explicitly test for fips mode + here. */ + if (DBG_CIPHER && !fips_mode ()) { - rc = gpg_err_code_from_syserror (); - goto leave; + log_debug ("pubkey_encrypt: algo=%d\n", spec->algo); + for(i = 0; i < pubkey_get_npkey (spec->algo); i++) + log_mpidump (" pkey", pkey[i]); + log_mpidump (" data", data); } - rc = pubkey_encrypt (spec->algo, ciph, data, pkey, ctx.flags); - mpi_free (data); - data = NULL; - if (rc) - goto leave; - /* We did it. Now build the return list */ - if (ctx.encoding == PUBKEY_ENC_OAEP - || ctx.encoding == PUBKEY_ENC_PKCS1) - { - /* We need to make sure to return the correct length to avoid - problems with missing leading zeroes. We know that this - encoding does only make sense with RSA thus we don't need to - build the S-expression on the fly. */ - unsigned char *em; - size_t emlen = (ctx.nbits+7)/8; - - rc = octet_string_from_mpi (&em, NULL, ciph[0], emlen); - if (rc) - goto leave; - rc = gcry_err_code (gcry_sexp_build (r_ciph, NULL, - "(enc-val(%s(a%b)))", - algo_name, (int)emlen, em)); - gcry_free (em); - if (rc) - goto leave; - } + if (spec->encrypt) + rc = spec->encrypt (spec->algo, r_ciph, data, pkey, ctx.flags); else - { - char *string, *p; - int i; - size_t nelem = strlen (algo_elems); - size_t needed = 19 + strlen (algo_name) + (nelem * 5); - void **arg_list; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } - p = stpcpy ( p, "(enc-val(" ); - p = stpcpy ( p, algo_name ); - for (i=0; algo_elems[i]; i++ ) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy ( p, "%m)" ); - } - strcpy ( p, "))" ); - - /* And now the ugly part: We don't have a function to pass an - * array to a format string, so we have to do it this way :-(. */ - /* FIXME: There is now such a format specifier, so we can - change the code to be more clear. */ - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } + rc = GPG_ERR_NOT_IMPLEMENTED; - for (i = 0; i < nelem; i++) - arg_list[i] = ciph + i; - rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } + /* if (DBG_CIPHER && !fips_mode ()) */ + /* { */ + /* for (i = 0; i < pubkey_get_nenc (spec->algo); i++) */ + /* log_mpidump (" encr", ciph[i]); */ + /* } */ leave: + mpi_free (data); if (pkey) { release_mpi_array (pkey); gcry_free (pkey); } - if (ciph) - { - release_mpi_array (ciph); - gcry_free (ciph); - } - gcry_free (ctx.label); return gcry_error (rc); @@ -2814,16 +2542,17 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) gcry_mpi_t plain = NULL; unsigned char *unpad = NULL; size_t unpadlen = 0; + int i; int modern, flags; struct pk_encoding_ctx ctx; + gcry_pk_spec_t *spec = NULL; gcry_pk_spec_t *spec_enc = NULL; - gcry_pk_spec_t *spec_key = NULL; *r_plain = NULL; ctx.label = NULL; rc = sexp_to_key (s_skey, 1, GCRY_PK_USAGE_ENCR, NULL, - &skey, &spec_key, NULL); + &skey, &spec, NULL); if (rc) goto leave; @@ -2832,16 +2561,31 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) if (rc) goto leave; - if (spec_key->algo != spec_enc->algo) + if (spec->algo != spec_enc->algo) { rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ goto leave; } - rc = pubkey_decrypt (spec_key->algo, &plain, data, skey, flags); + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("gcry_pk_decrypt: algo=%d\n", spec->algo); + for(i = 0; i < pubkey_get_nskey (spec->algo); i++) + log_mpidump (" skey", skey[i]); + for(i = 0; i < pubkey_get_nenc (spec->algo); i++) + log_mpidump (" data", data[i]); + } + + if (spec->decrypt) + rc = spec->decrypt (spec->algo, &plain, data, skey, flags); + else + rc = GPG_ERR_NOT_IMPLEMENTED; if (rc) goto leave; + if (DBG_CIPHER && !fips_mode ()) + log_mpidump (" plain", plain); + /* Do un-padding if necessary. */ switch (ctx.encoding) { @@ -2931,9 +2675,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) { gcry_mpi_t *skey = NULL; gcry_mpi_t hash = NULL; - gcry_mpi_t *result = NULL; gcry_pk_spec_t *spec = NULL; - const char *algo_name, *algo_elems; struct pk_encoding_ctx ctx; int i; int is_ecc; @@ -2947,11 +2689,6 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) goto leave; gcry_assert (spec); - algo_name = spec->aliases? *spec->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = spec->name; - - algo_elems = spec->elements_sig; /* Get the stuff we want to sign. Note that pk_get_nbits does also work on a private key. We don't need the number of bits for ECC @@ -2962,81 +2699,26 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) if (rc) goto leave; - result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result)); - if (!result) + if (DBG_CIPHER && !fips_mode ()) { - rc = gpg_err_code_from_syserror (); - goto leave; + log_debug ("gcry_pk_sign: algo=%d\n", spec->algo); + for(i = 0; i < pubkey_get_nskey (spec->algo); i++) + log_mpidump (" skey", skey[i]); + log_mpidump(" data", hash); } - rc = pubkey_sign (spec->algo, result, hash, skey, &ctx); - if (rc) - goto leave; - if (ctx.encoding == PUBKEY_ENC_PSS - || ctx.encoding == PUBKEY_ENC_PKCS1) - { - /* We need to make sure to return the correct length to avoid - problems with missing leading zeroes. We know that this - encoding does only make sense with RSA thus we don't need to - build the S-expression on the fly. */ - unsigned char *em; - size_t emlen = (ctx.nbits+7)/8; - - rc = octet_string_from_mpi (&em, NULL, result[0], emlen); - if (rc) - goto leave; - rc = gcry_err_code (gcry_sexp_build (r_sig, NULL, - "(sig-val(%s(s%b)))", - algo_name, (int)emlen, em)); - gcry_free (em); - if (rc) - goto leave; - } + if (spec->sign) + rc = spec->sign (spec->algo, r_sig, hash, skey, ctx.flags, ctx.hash_algo); else - { - /* General purpose output encoding. Do it on the fly. */ - char *string, *p; - size_t nelem, needed = strlen (algo_name) + 20; - void **arg_list; - - nelem = strlen (algo_elems); - - /* Count elements, so that we can allocate enough space. */ - needed += 10 * nelem; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } - p = stpcpy (p, "(sig-val("); - p = stpcpy (p, algo_name); - for (i = 0; algo_elems[i]; i++) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy (p, "%M)"); - } - strcpy (p, "))"); - - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } + rc = GPG_ERR_NOT_IMPLEMENTED; - for (i = 0; i < nelem; i++) - arg_list[i] = result + i; + if (rc) + goto leave; - rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } + /* Fixme: To print the result we need to print an sexp. */ + /* if (!rc && DBG_CIPHER && !fips_mode ()) */ + /* for (i = 0; i < pubkey_get_nsig (algo); i++) */ + /* log_mpidump (" sig", resarr[i]); */ leave: if (skey) @@ -3054,14 +2736,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) gcry_free (skey); } - if (hash) - mpi_free (hash); - - if (result) - { - release_mpi_array (result); - gcry_free (result); - } + mpi_free (hash); return gcry_error (rc); } @@ -3078,15 +2753,16 @@ gcry_error_t gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) { gcry_err_code_t rc; - gcry_pk_spec_t *spec_key = NULL; + gcry_pk_spec_t *spec = NULL; gcry_pk_spec_t *spec_sig = NULL; gcry_mpi_t *pkey = NULL; gcry_mpi_t hash = NULL; gcry_mpi_t *sig = NULL; struct pk_encoding_ctx ctx; + int i; rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_SIGN, NULL, - &pkey, &spec_key, NULL); + &pkey, &spec, NULL); if (rc) goto leave; @@ -3104,13 +2780,28 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) /* Fixme: Check that the algorithm of S_SIG is compatible to the one of S_PKEY. */ - if (spec_key->algo != spec_sig->algo) + if (spec->algo != spec_sig->algo) { rc = GPG_ERR_CONFLICT; goto leave; } - rc = pubkey_verify (spec_key->algo, hash, sig, pkey, &ctx); + if (DBG_CIPHER && !fips_mode ()) + { + log_debug ("gcry_pk_verify: algo=%d\n", spec->algo); + for (i = 0; i < pubkey_get_npkey (spec->algo); i++) + log_mpidump (" pkey", pkey[i]); + for (i = 0; i < pubkey_get_nsig (spec->algo); i++) + log_mpidump (" sig", sig[i]); + log_mpidump (" hash", hash); + } + + if (spec->verify) + rc = spec->verify (spec->algo, hash, sig, pkey, + ctx.verify_cmp, &ctx, ctx.flags, ctx.hash_algo); + else + rc = GPG_ERR_NOT_IMPLEMENTED; + leave: if (pkey) diff --git a/cipher/rsa.c b/cipher/rsa.c index e495cd85..91349db1 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -893,20 +893,43 @@ rsa_check_secret_key (int algo, gcry_mpi_t *skey) static gcry_err_code_t -rsa_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, +rsa_encrypt (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *pkey, int flags) { + gpg_err_code_t rc; RSA_public_key pk; + gcry_mpi_t result; (void)algo; (void)flags; pk.n = pkey[0]; pk.e = pkey[1]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.n)); - public (resarr[0], data, &pk); + result = mpi_alloc (mpi_get_nlimbs (pk.n)); + public (result, data, &pk); + if ((flags & PUBKEY_FLAG_FIXEDLEN)) + { + /* We need to make sure to return the correct length to avoid + problems with missing leading zeroes. */ + unsigned char *em; + size_t emlen = (mpi_get_nbits (pk.n)+7)/8; - return GPG_ERR_NO_ERROR; + rc = _gcry_mpi_to_octet_string (&em, NULL, result, emlen); + if (!rc) + { + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(enc-val(rsa(a%b)))", + (int)emlen, em)); + gcry_free (em); + } + } + else + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(enc-val(rsa(a%m)))", + result)); + + mpi_free (result); + return rc; } @@ -993,10 +1016,12 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, static gcry_err_code_t -rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, +rsa_sign (int algo, gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey, int flags, int hashalgo) { + gpg_err_code_t rc; RSA_secret_key sk; + gcry_mpi_t result; (void)algo; (void)flags; @@ -1011,10 +1036,31 @@ rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey, sk.p = skey[3]; sk.q = skey[4]; sk.u = skey[5]; - resarr[0] = mpi_alloc( mpi_get_nlimbs (sk.n)); - secret (resarr[0], data, &sk); + result = mpi_alloc (mpi_get_nlimbs (sk.n)); + secret (result, data, &sk); + if ((flags & PUBKEY_FLAG_FIXEDLEN)) + { + /* We need to make sure to return the correct length to avoid + problems with missing leading zeroes. */ + unsigned char *em; + size_t emlen = (mpi_get_nbits (sk.n)+7)/8; - return GPG_ERR_NO_ERROR; + rc = _gcry_mpi_to_octet_string (&em, NULL, result, emlen); + if (!rc) + { + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(sig-val(rsa(s%b)))", + (int)emlen, em)); + gcry_free (em); + } + } + else + rc = gcry_err_code (gcry_sexp_build (r_result, NULL, + "(sig-val(rsa(s%M)))", + result)); + mpi_free (result); + + return rc; } diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index 07e91c63..1d2c87e0 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -836,3 +836,61 @@ gcry_mpi_aprint (enum gcry_mpi_format format, *nwritten = n; return rc; } + + +/* Turn VALUE into an octet string and store it in an allocated buffer + at R_FRAME or - if R_RAME is NULL - copy it into the caller + provided buffer SPACE; either SPACE or R_FRAME may be used. If + SPACE if not NULL, the caller must provide a buffer of at least + NBYTES. If the resulting octet string is shorter than NBYTES pad + it to the left with zeroes. If VALUE does not fit into NBYTES + return an error code. */ +gpg_err_code_t +_gcry_mpi_to_octet_string (unsigned char **r_frame, void *space, + gcry_mpi_t value, size_t nbytes) +{ + gpg_err_code_t rc; + size_t nframe, noff, n; + unsigned char *frame; + + if (!r_frame == !space) + return GPG_ERR_INV_ARG; /* Only one may be used. */ + + if (r_frame) + *r_frame = NULL; + + rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, + NULL, 0, &nframe, value)); + if (rc) + return rc; + if (nframe > nbytes) + return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */ + + noff = (nframe < nbytes)? nbytes - nframe : 0; + n = nframe + noff; + if (space) + frame = space; + else + { + frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n); + if (!frame) + { + rc = gpg_err_code_from_syserror (); + return rc; + } + } + if (noff) + memset (frame, 0, noff); + nframe += noff; + rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, + frame+noff, nframe-noff, NULL, value)); + if (rc) + { + gcry_free (frame); + return rc; + } + + if (r_frame) + *r_frame = frame; + return 0; +} diff --git a/src/cipher-proto.h b/src/cipher-proto.h index a641a079..121d9f57 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -68,7 +68,7 @@ typedef gcry_err_code_t (*gcry_pk_check_secret_key_t) (int algo, /* Type for the pk_encrypt function. */ typedef gcry_err_code_t (*gcry_pk_encrypt_t) (int algo, - gcry_mpi_t *resarr, + gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *pkey, int flags); @@ -82,7 +82,7 @@ typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo, /* Type for the pk_sign function. */ typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo, - gcry_mpi_t *resarr, + gcry_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey, int flags, diff --git a/src/cipher.h b/src/cipher.h index 8d3afbfa..dde24ceb 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -29,6 +29,7 @@ #define PUBKEY_FLAG_NO_BLINDING (1 << 0) #define PUBKEY_FLAG_RFC6979 (1 << 1) #define PUBKEY_FLAG_EDDSA (1 << 2) +#define PUBKEY_FLAG_FIXEDLEN (1 << 3) enum pk_operation { @@ -167,6 +167,9 @@ byte *_gcry_mpi_get_secure_buffer (gcry_mpi_t a, unsigned int fill_le, unsigned *r_nbytes, int *sign); void _gcry_mpi_set_buffer ( gcry_mpi_t a, const void *buffer, unsigned int nbytes, int sign ); +gpg_err_code_t _gcry_mpi_to_octet_string (unsigned char **r_frame, + void *space, + gcry_mpi_t value, size_t nbytes); /*-- mpi-add.c --*/ #define mpi_add_ui(w,u,v) gcry_mpi_add_ui((w),(u),(v)) diff --git a/tests/t-ed25519.c b/tests/t-ed25519.c index e1139136..baa6a7ad 100644 --- a/tests/t-ed25519.c +++ b/tests/t-ed25519.c @@ -326,7 +326,7 @@ one_test (int testno, const char *sk, const char *pk, if (s_tmp) { s_tmp2 = s_tmp; - s_tmp = gcry_sexp_find_token (s_tmp2, "ecdsa", 0); + s_tmp = gcry_sexp_find_token (s_tmp2, "eddsa", 0); if (s_tmp) { gcry_sexp_release (s_tmp2); |