/* Parse a "enc-val" s-expression and store the inner parameter list at R_PARMS. ALGO_NAMES is used to verify that the algorithm in "enc-val" is valid. Returns 0 on success and stores a new list at R_PARMS which must be freed by the caller. On error R_PARMS is set to NULL and an error code returned. If R_ECCFLAGS is not NULL flag values are set into it; as of now they are only used with ecc algorithms. (enc-val [(flags [raw, pkcs1, oaep, no-blinding])] [(hash-algo <algo>)] [(label <label>)] (<algo> (<param_name1> <mpi>) ... (<param_namen> <mpi>))) HASH-ALGO and LABEL are specific to OAEP. CTX will be updated with encoding information. */ gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, gcry_sexp_t *r_parms, struct pk_encoding_ctx *ctx) { gcry_err_code_t rc = 0; gcry_sexp_t l1 = NULL; gcry_sexp_t l2 = NULL; char *name = NULL; size_t n; int parsed_flags = 0; int i; *r_parms = NULL; /* Check that the first element is valid. */ l1 = sexp_find_token (sexp, "enc-val" , 0); if (!l1) { rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ goto leave; } l2 = sexp_nth (l1, 1); if (!l2) { rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ goto leave; } /* Extract identifier of sublist. */ name = sexp_nth_string (l2, 0); if (!name) { rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ goto leave; } if (!strcmp (name, "flags")) { const char *s; /* There is a flags element - process it. */ rc = _gcry_pk_util_parse_flaglist (l2, &parsed_flags, &ctx->encoding); if (rc) goto leave; if (ctx->encoding == PUBKEY_ENC_PSS) { rc = GPG_ERR_CONFLICT; goto leave; } /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */ if (ctx->encoding == PUBKEY_ENC_OAEP) { /* Get HASH-ALGO. */ sexp_release (l2); l2 = sexp_find_token (l1, "hash-algo", 0); if (l2) { s = sexp_nth_data (l2, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else { ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; } if (rc) goto leave; } /* Get LABEL. */ sexp_release (l2); l2 = sexp_find_token (l1, "label", 0); if (l2) { s = sexp_nth_data (l2, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else if (n > 0) { ctx->label = xtrymalloc (n); if (!ctx->label) rc = gpg_err_code_from_syserror (); else { memcpy (ctx->label, s, n); ctx->labellen = n; } } if (rc) goto leave; } } /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */ for (i = 2; (sexp_release (l2), l2 = sexp_nth (l1, i)); i++) { s = sexp_nth_data (l2, 0, &n); if (!(n == 9 && !memcmp (s, "hash-algo", 9)) && !(n == 5 && !memcmp (s, "label", 5)) && !(n == 15 && !memcmp (s, "random-override", 15))) break; } if (!l2) { rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ goto leave; } /* Extract sublist identifier. */ xfree (name); name = sexp_nth_string (l2, 0); if (!name) { rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ goto leave; } } else /* No flags - flag as legacy structure. */ parsed_flags |= PUBKEY_FLAG_LEGACYRESULT; for (i=0; algo_names[i]; i++) if (!stricmp (name, algo_names[i])) break; if (!algo_names[i]) { rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */ goto leave; } *r_parms = l2; l2 = NULL; ctx->flags |= parsed_flags; rc = 0; leave: xfree (name); sexp_release (l2); sexp_release (l1); return rc; }
/* Take the hash value and convert into an MPI, suitable for passing to the low level functions. We currently support the old style way of passing just a MPI and the modern interface which allows to pass flags so that we can choose between raw and pkcs1 padding - may be more padding options later. (<mpi>) or (data [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])] [(hash <algo> <value>)] [(value <text>)] [(hash-algo <algo>)] [(label <label>)] [(salt-length <length>)] [(random-override <data>)] ) Either the VALUE or the HASH element must be present for use with signatures. VALUE is used for encryption. HASH-ALGO is specific to OAEP and EDDSA. LABEL is specific to OAEP. SALT-LENGTH is for PSS. RANDOM-OVERRIDE is used to replace random nonces for regression testing. */ gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, struct pk_encoding_ctx *ctx) { gcry_err_code_t rc = 0; gcry_sexp_t ldata, lhash, lvalue; size_t n; const char *s; int unknown_flag = 0; int parsed_flags = 0; *ret_mpi = NULL; ldata = sexp_find_token (input, "data", 0); if (!ldata) { /* assume old style */ *ret_mpi = sexp_nth_mpi (input, 0, 0); return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; } /* See whether there is a flags list. */ { gcry_sexp_t lflags = sexp_find_token (ldata, "flags", 0); if (lflags) { if (_gcry_pk_util_parse_flaglist (lflags, &parsed_flags, &ctx->encoding)) unknown_flag = 1; sexp_release (lflags); } } if (ctx->encoding == PUBKEY_ENC_UNKNOWN) ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */ /* Get HASH or MPI */ lhash = sexp_find_token (ldata, "hash", 0); lvalue = lhash? NULL : sexp_find_token (ldata, "value", 0); if (!(!lhash ^ !lvalue)) rc = GPG_ERR_INV_OBJ; /* none or both given */ else if (unknown_flag) rc = GPG_ERR_INV_FLAG; else if (ctx->encoding == PUBKEY_ENC_RAW && (parsed_flags & PUBKEY_FLAG_EDDSA)) { /* Prepare for EdDSA. */ gcry_sexp_t list; void *value; size_t valuelen; if (!lvalue) { rc = GPG_ERR_INV_OBJ; goto leave; } /* Get HASH-ALGO. */ list = sexp_find_token (ldata, "hash-algo", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else { ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; } sexp_release (list); } else rc = GPG_ERR_INV_OBJ; if (rc) goto leave; /* Get VALUE. */ value = sexp_nth_buffer (lvalue, 1, &valuelen); if (!value) { /* We assume that a zero length message is meant by "(value)". This is commonly used by test vectors. Note that S-expression do not allow zero length items. */ valuelen = 0; value = xtrymalloc (1); if (!value) rc = gpg_err_code_from_syserror (); } else if ((valuelen * 8) < valuelen) { xfree (value); rc = GPG_ERR_TOO_LARGE; } if (rc) goto leave; /* Note that mpi_set_opaque takes ownership of VALUE. */ *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8); } else if (ctx->encoding == PUBKEY_ENC_RAW && lhash && ((parsed_flags & PUBKEY_FLAG_RAW_FLAG) || (parsed_flags & PUBKEY_FLAG_RFC6979))) { /* Raw encoding along with a hash element. This is commonly used for DSA. For better backward error compatibility we allow this only if either the rfc6979 flag has been given or the raw flags was explicitly given. */ if (sexp_length (lhash) != 3) rc = GPG_ERR_INV_OBJ; else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) rc = GPG_ERR_INV_OBJ; else { void *value; size_t valuelen; ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; else if (!(value=sexp_nth_buffer (lhash, 2, &valuelen))) rc = GPG_ERR_INV_OBJ; else if ((valuelen * 8) < valuelen) { xfree (value); rc = GPG_ERR_TOO_LARGE; } else *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8); } } else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue) { /* RFC6969 may only be used with the a hash value and not the MPI based value. */ if (parsed_flags & PUBKEY_FLAG_RFC6979) { rc = GPG_ERR_CONFLICT; goto leave; } /* Get the value */ *ret_mpi = sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG); if (!*ret_mpi) rc = GPG_ERR_INV_OBJ; } else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue && ctx->op == PUBKEY_OP_ENCRYPT) { const void * value; size_t valuelen; gcry_sexp_t list; void *random_override = NULL; size_t random_override_len = 0; if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) rc = GPG_ERR_INV_OBJ; else { /* Get optional RANDOM-OVERRIDE. */ list = sexp_find_token (ldata, "random-override", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else if (n > 0) { random_override = xtrymalloc (n); if (!random_override) rc = gpg_err_code_from_syserror (); else { memcpy (random_override, s, n); random_override_len = n; } } sexp_release (list); if (rc) goto leave; } rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits, value, valuelen, random_override, random_override_len); xfree (random_override); } } else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY)) { if (sexp_length (lhash) != 3) rc = GPG_ERR_INV_OBJ; else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) rc = GPG_ERR_INV_OBJ; else { const void * value; size_t valuelen; ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; else if ( !(value=sexp_nth_data (lhash, 2, &valuelen)) || !valuelen ) rc = GPG_ERR_INV_OBJ; else rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits, value, valuelen, ctx->hash_algo); } } else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue && ctx->op == PUBKEY_OP_ENCRYPT) { const void * value; size_t valuelen; if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) rc = GPG_ERR_INV_OBJ; else { gcry_sexp_t list; void *random_override = NULL; size_t random_override_len = 0; /* Get HASH-ALGO. */ list = sexp_find_token (ldata, "hash-algo", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else { ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; } sexp_release (list); if (rc) goto leave; } /* Get LABEL. */ list = sexp_find_token (ldata, "label", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else if (n > 0) { ctx->label = xtrymalloc (n); if (!ctx->label) rc = gpg_err_code_from_syserror (); else { memcpy (ctx->label, s, n); ctx->labellen = n; } } sexp_release (list); if (rc) goto leave; } /* Get optional RANDOM-OVERRIDE. */ list = sexp_find_token (ldata, "random-override", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else if (n > 0) { random_override = xtrymalloc (n); if (!random_override) rc = gpg_err_code_from_syserror (); else { memcpy (random_override, s, n); random_override_len = n; } } sexp_release (list); if (rc) goto leave; } rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo, value, valuelen, ctx->label, ctx->labellen, random_override, random_override_len); xfree (random_override); } } else if (ctx->encoding == PUBKEY_ENC_PSS && lhash && ctx->op == PUBKEY_OP_SIGN) { if (sexp_length (lhash) != 3) rc = GPG_ERR_INV_OBJ; else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) rc = GPG_ERR_INV_OBJ; else { const void * value; size_t valuelen; void *random_override = NULL; size_t random_override_len = 0; ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; else if ( !(value=sexp_nth_data (lhash, 2, &valuelen)) || !valuelen ) rc = GPG_ERR_INV_OBJ; else { gcry_sexp_t list; /* Get SALT-LENGTH. */ list = sexp_find_token (ldata, "salt-length", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) { rc = GPG_ERR_NO_OBJ; goto leave; } ctx->saltlen = (unsigned int)strtoul (s, NULL, 10); sexp_release (list); } /* Get optional RANDOM-OVERRIDE. */ list = sexp_find_token (ldata, "random-override", 0); if (list) { s = sexp_nth_data (list, 1, &n); if (!s) rc = GPG_ERR_NO_OBJ; else if (n > 0) { random_override = xtrymalloc (n); if (!random_override) rc = gpg_err_code_from_syserror (); else { memcpy (random_override, s, n); random_override_len = n; } } sexp_release (list); if (rc) goto leave; } /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */ rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo, value, valuelen, ctx->saltlen, random_override, random_override_len); xfree (random_override); } } } else if (ctx->encoding == PUBKEY_ENC_PSS && lhash && ctx->op == PUBKEY_OP_VERIFY) { if (sexp_length (lhash) != 3) rc = GPG_ERR_INV_OBJ; else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) rc = GPG_ERR_INV_OBJ; else { ctx->hash_algo = get_hash_algo (s, n); if (!ctx->hash_algo) rc = GPG_ERR_DIGEST_ALGO; else { *ret_mpi = sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG); if (!*ret_mpi) rc = GPG_ERR_INV_OBJ; ctx->verify_cmp = pss_verify_cmp; ctx->verify_arg = *ret_mpi; } } } else rc = GPG_ERR_CONFLICT; leave: sexp_release (ldata); sexp_release (lhash); sexp_release (lvalue); if (!rc) ctx->flags = parsed_flags; else { xfree (ctx->label); ctx->label = NULL; } return rc; }
/* This function creates a new context for elliptic curve operations. Either KEYPARAM or CURVENAME must be given. If both are given and KEYPARAM has no curve parameter, CURVENAME is used to add missing parameters. On success 0 is returned and the new context stored at R_CTX. On error NULL is stored at R_CTX and an error code is returned. The context needs to be released using gcry_ctx_release. */ gpg_err_code_t _gcry_mpi_ec_new (gcry_ctx_t *r_ctx, gcry_sexp_t keyparam, const char *curvename) { gpg_err_code_t errc; gcry_ctx_t ctx = NULL; enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS; enum ecc_dialects dialect = ECC_DIALECT_STANDARD; gcry_mpi_t p = NULL; gcry_mpi_t a = NULL; gcry_mpi_t b = NULL; gcry_mpi_point_t G = NULL; gcry_mpi_t n = NULL; gcry_mpi_point_t Q = NULL; gcry_mpi_t d = NULL; int flags = 0; gcry_sexp_t l1; *r_ctx = NULL; if (keyparam) { /* Parse an optional flags list. */ l1 = sexp_find_token (keyparam, "flags", 0); if (l1) { errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); sexp_release (l1); l1 = NULL; if (errc) goto leave; } /* Check whether a curve name was given. */ l1 = sexp_find_token (keyparam, "curve", 5); /* If we don't have a curve name or if override parameters have explicitly been requested, parse them. */ if (!l1 || (flags & PUBKEY_FLAG_PARAM)) { errc = mpi_from_keyparam (&p, keyparam, "p"); if (errc) goto leave; errc = mpi_from_keyparam (&a, keyparam, "a"); if (errc) goto leave; errc = mpi_from_keyparam (&b, keyparam, "b"); if (errc) goto leave; errc = point_from_keyparam (&G, keyparam, "g", NULL); if (errc) goto leave; errc = mpi_from_keyparam (&n, keyparam, "n"); if (errc) goto leave; } } else l1 = NULL; /* No curvename. */ /* Check whether a curve parameter is available and use that to fill in missing values. If no curve parameter is available try an optional provided curvename. If only the curvename has been given use that one. */ if (l1 || curvename) { char *name; elliptic_curve_t *E; if (l1) { name = sexp_nth_string (l1, 1); sexp_release (l1); if (!name) { errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ goto leave; } } else name = NULL; E = xtrycalloc (1, sizeof *E); if (!E) { errc = gpg_err_code_from_syserror (); xfree (name); goto leave; } errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL); xfree (name); if (errc) { xfree (E); goto leave; } model = E->model; dialect = E->dialect; if (!p) { p = E->p; E->p = NULL; } if (!a) { a = E->a; E->a = NULL; } if (!b) { b = E->b; E->b = NULL; } if (!G) { G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z); E->G.x = NULL; E->G.y = NULL; E->G.z = NULL; } if (!n) { n = E->n; E->n = NULL; } _gcry_ecc_curve_free (E); xfree (E); } errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, flags, p, a, b); if (!errc) { mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); if (b) { mpi_free (ec->b); ec->b = b; b = NULL; } if (G) { ec->G = G; G = NULL; } if (n) { ec->n = n; n = NULL; } /* Now that we know the curve name we can look for the public key Q. point_from_keyparam needs to know the curve parameters so that it is able to use the correct decompression. Parsing the private key D could have been done earlier but it is less surprising if we do it here as well. */ if (keyparam) { errc = point_from_keyparam (&Q, keyparam, "q", ec); if (errc) goto leave; errc = mpi_from_keyparam (&d, keyparam, "d"); if (errc) goto leave; } if (Q) { ec->Q = Q; Q = NULL; } if (d) { ec->d = d; d = NULL; } *r_ctx = ctx; ctx = NULL; } leave: _gcry_ctx_release (ctx); mpi_free (p); mpi_free (a); mpi_free (b); _gcry_mpi_point_release (G); mpi_free (n); _gcry_mpi_point_release (Q); mpi_free (d); return errc; }