/* pkey.c - pubric key cryptography API * Copyright (C) 2021 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ #include #include #include #include #include #include #include "g10lib.h" #include "gcrypt-int.h" #include "pkey-internal.h" gcry_error_t _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags, va_list arg_ptr) { gcry_error_t err = 0; gcry_pkey_hd_t h; if (algo == GCRY_PKEY_ECC) ; else if (algo == GCRY_PKEY_RSA) ; else if (algo == GCRY_PKEY_DSA) err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); else if (algo == GCRY_PKEY_ELG) err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); else err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); if (err) return err; if (!(h = xtrycalloc (1, sizeof (struct gcry_pkey_handle)))) return gpg_err_code_from_syserror (); h->algo = algo; h->flags = flags; if (algo == GCRY_PKEY_ECC) { int curve; unsigned char *pk; unsigned char *sk; curve = va_arg (arg_ptr, int); if (curve == GCRY_PKEY_CURVE_ED25519) ; else if (curve == GCRY_PKEY_CURVE_ED448) ; else err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); if (err) { xfree (h); return err; } h->ecc.curve = curve; if (!(flags & GCRY_PKEY_FLAG_SECRET)) { pk = va_arg (arg_ptr, unsigned char *); h->ecc.pk_len = va_arg (arg_ptr, size_t); h->ecc.sk = sk = NULL; h->ecc.sk_len = 0; } else { pk = va_arg (arg_ptr, unsigned char *); h->ecc.pk_len = va_arg (arg_ptr, size_t); sk = va_arg (arg_ptr, unsigned char *); h->ecc.sk_len = va_arg (arg_ptr, size_t); } if (err) { xfree (h); return err; } if (pk) { h->ecc.pk = xtrymalloc (h->ecc.pk_len); if (!h->ecc.pk) { err = gpg_err_code_from_syserror (); xfree (h); return err; } memcpy (h->ecc.pk, pk, h->ecc.pk_len); } else h->ecc.pk = NULL; if (sk) { h->ecc.sk = xtrymalloc_secure (h->ecc.sk_len); if (!h->ecc.sk) { err = gpg_err_code_from_syserror (); xfree (h->ecc.pk); xfree (h); return err; } memcpy (h->ecc.sk, sk, h->ecc.sk_len); } } else if (algo == GCRY_PKEY_RSA) { int scheme; int md_algo; unsigned char *n; unsigned char *e; unsigned char *d; scheme = va_arg (arg_ptr, int); if (scheme == GCRY_PKEY_RSA_PSS) ; else if (scheme == GCRY_PKEY_RSA_15) ; else if (scheme == GCRY_PKEY_RSA_931) err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); else err = gpg_error (GPG_ERR_INV_ARG); if (err) { xfree (h); return err; } h->rsa.scheme = scheme; md_algo = va_arg (arg_ptr, int); h->rsa.md_algo = md_algo; if (!(flags & GCRY_PKEY_FLAG_SECRET)) { n = va_arg (arg_ptr, unsigned char *); h->rsa.n_len = va_arg (arg_ptr, size_t); e = va_arg (arg_ptr, unsigned char *); h->rsa.e_len = va_arg (arg_ptr, size_t); h->rsa.d = d = NULL; h->rsa.d_len = 0; } else { n = va_arg (arg_ptr, unsigned char *); h->rsa.n_len = va_arg (arg_ptr, size_t); e = va_arg (arg_ptr, unsigned char *); h->rsa.e_len = va_arg (arg_ptr, size_t); d = va_arg (arg_ptr, unsigned char *); h->rsa.d_len = va_arg (arg_ptr, size_t); } if (err) { xfree (h); return err; } if (n) { h->rsa.n = xtrymalloc (h->rsa.n_len); if (!h->rsa.n) { err = gpg_err_code_from_syserror (); xfree (h); return err; } memcpy (h->rsa.n, n, h->rsa.n_len); } else h->rsa.n = NULL; if (e) { h->rsa.e = xtrymalloc (h->rsa.e_len); if (!h->rsa.e) { err = gpg_err_code_from_syserror (); xfree (h); return err; } memcpy (h->rsa.e, e, h->rsa.e_len); } else h->rsa.e = NULL; if (d) { h->rsa.d = xtrymalloc (h->rsa.d_len); if (!h->rsa.d) { err = gpg_err_code_from_syserror (); xfree (h); return err; } memcpy (h->rsa.d, d, h->rsa.d_len); } } *h_p = h; return err; } gcry_error_t _gcry_pkey_ctl (gcry_pkey_hd_t h, int cmd, void *buffer, size_t buflen) { gcry_error_t err = 0; (void)h; (void)cmd; (void)buffer; (void)buflen; /* FIXME: Not yet implemented anything. */ return err; } /* For now, it uses SEXP implementation, because the purpose is to test the API (but not the implementation). Will be rewritten soon. Currently, it's like: [ gcry_pkey_op API (with binary data) ] | [ gcry_pk_ API (with SEXP) ] | [ lower level public key implementations (with SEXP) ] It will be like: [ gcry_pk_ API with SEXP ] [ gcry_pkey_op API with binary data ] | | [ lower level public key implementations ] That is, lower level public key implementations won't have any (direct) handling of SEXP. */ gcry_error_t _gcry_pkey_op (gcry_pkey_hd_t h, int cmd, int num_in, const unsigned char *const in[], const size_t in_len[], int num_out, unsigned char *out[], size_t out_len[]) { gcry_error_t err = 0; if (h->algo == GCRY_PKEY_ECC) { /* Just for Ed25519 and Ed448 for now. Will support more... */ if (h->ecc.curve == GCRY_PKEY_CURVE_ED25519) { if (cmd == GCRY_PKEY_OP_SIGN) err = _gcry_pkey_ed25519_sign (h, num_in, in, in_len, num_out, out, out_len); else if (cmd == GCRY_PKEY_OP_VERIFY) err = _gcry_pkey_ed25519_verify (h, num_in, in, in_len); else err = gpg_error (GPG_ERR_INV_OP); } else if (h->ecc.curve == GCRY_PKEY_CURVE_ED448) { if (cmd == GCRY_PKEY_OP_SIGN) err = _gcry_pkey_ed448_sign (h, num_in, in, in_len, num_out, out, out_len); else if (cmd == GCRY_PKEY_OP_VERIFY) err = _gcry_pkey_ed448_verify (h, num_in, in, in_len); else err = gpg_error (GPG_ERR_INV_OP); } else err = gpg_error (GPG_ERR_INV_OP); } else if (h->algo == GCRY_PKEY_RSA) { if (h->rsa.scheme == GCRY_PKEY_RSA_PSS) { if (cmd == GCRY_PKEY_OP_SIGN) err = _gcry_pkey_rsapss_sign (h, num_in, in, in_len, num_out, out, out_len); else if (cmd == GCRY_PKEY_OP_VERIFY) err = _gcry_pkey_rsapss_verify (h, num_in, in, in_len); else err = gpg_error (GPG_ERR_INV_OP); } else if (h->rsa.scheme == GCRY_PKEY_RSA_15) { if (cmd == GCRY_PKEY_OP_SIGN) err = _gcry_pkey_rsa15_sign (h, num_in, in, in_len, num_out, out, out_len); else if (cmd == GCRY_PKEY_OP_VERIFY) err = _gcry_pkey_rsa15_verify (h, num_in, in, in_len); else err = gpg_error (GPG_ERR_INV_OP); } else err = gpg_error (GPG_ERR_INV_OP); } else err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); return err; } void _gcry_pkey_close (gcry_pkey_hd_t h) { if (h) { if (h->algo == GCRY_PKEY_ECC) { xfree (h->ecc.pk); xfree (h->ecc.sk); } else if (h->algo == GCRY_PKEY_RSA) { xfree (h->rsa.n); xfree (h->rsa.e); xfree (h->rsa.d); } xfree (h); } }