static int generate_subkey( cdk_keygen_ctx_t hd ) { gcry_sexp_t s_params = NULL, s_key; size_t n = hd->key[1].len; int rc; if( !hd ) return CDK_Inv_Value; if( is_DSA( hd->key[1].algo) ) rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n ); else if( is_ELG( hd->key[1].algo) ) rc = gcry_sexp_build( &s_params, NULL, "(genkey(elg(nbits %d)))", n ); else if( is_RSA( hd->key[1].algo) ) rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n ); else rc = CDK_Inv_Algo; if( !rc ) rc = gcry_pk_genkey( &s_key, s_params ); gcry_sexp_release( s_params ); if( !rc ) { if( is_DSA( hd->key[1].algo) ) rc = read_dsa_key( s_key, hd->key[1].resarr ); else if( is_ELG( hd->key[1].algo) ) rc = read_elg_key( s_key, hd->key[1].resarr ); else if( is_RSA( hd->key[1].algo) ) rc = read_rsa_key( s_key, hd->key[1].resarr ); } hd->key[1].n = cdk_pk_get_npkey( hd->key[1].algo ); gcry_sexp_release( s_key ); return rc; }
/** * gnutls_openpgp_key_get_key_usage - This function returns the key's usage * @key: should contain a gnutls_openpgp_key_t structure * @key_usage: where the key usage bits will be stored * * This function will return certificate's key usage, by checking the * key algorithm. The key usage value will ORed values of the: * GNUTLS_KEY_DIGITAL_SIGNATURE, GNUTLS_KEY_KEY_ENCIPHERMENT. * * A negative value may be returned in case of parsing error. * **/ int gnutls_openpgp_key_get_key_usage (gnutls_openpgp_key_t key, unsigned int *key_usage) { cdk_packet_t pkt; int algo = 0; if (!key) return GNUTLS_E_INVALID_REQUEST; *key_usage = 0; pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY); if (pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY) { algo = pkt->pkt.public_key->pubkey_algo; if (is_DSA (algo) || algo == GCRY_PK_RSA_S) *key_usage |= KEY_DIGITAL_SIGNATURE; else if (algo == GCRY_PK_RSA_E) *key_usage |= KEY_KEY_ENCIPHERMENT; else if (algo == GCRY_PK_RSA) *key_usage |= KEY_DIGITAL_SIGNATURE | KEY_KEY_ENCIPHERMENT; } return 0; }
static cdk_error_t sexp_to_sig (cdk_pkt_signature_t sig, gcry_sexp_t sexp) { if (!sig || !sexp) return CDK_Inv_Value; /* ElGamal signatures are not supported any longer. */ if (is_ELG (sig->pubkey_algo)) { _cdk_log_debug ("sexp_to_sig: unsupported signature type (ElGamal)\n"); return CDK_Not_Implemented; } if (is_RSA (sig->pubkey_algo)) return sexp_to_mpi (sexp, "s", &sig->mpi[0]); else if (is_DSA (sig->pubkey_algo)) { cdk_error_t rc; rc = sexp_to_mpi (sexp, "r", &sig->mpi[0]); if (!rc) rc = sexp_to_mpi (sexp, "s", &sig->mpi[1]); return rc; } return CDK_Inv_Algo; }
/* This function gets the signature parameters and encodes * them into a way for _gnutls_pk_verify to use. */ static cdk_error_t sig_to_datum (gnutls_datum_t * r_sig, cdk_pkt_signature_t sig) { int err; cdk_error_t rc; if (!r_sig || !sig) return CDK_Inv_Value; rc = 0; if (is_RSA (sig->pubkey_algo)) { err = _gnutls_mpi_dprint (sig->mpi[0], r_sig); if (err < 0) rc = map_gnutls_error (err); } else if (is_DSA (sig->pubkey_algo)) { err = _gnutls_encode_ber_rs (r_sig, sig->mpi[0], sig->mpi[1]); if (err < 0) rc = map_gnutls_error (err); } else rc = CDK_Inv_Algo; return rc; }
/** * gnutls_openpgp_privkey_get_subkey_pk_algorithm: * @key: is an OpenPGP key * @idx: is the subkey index * @bits: if bits is non null it will hold the size of the parameters' in bits * * This function will return the public key algorithm of a subkey of an OpenPGP * certificate. * * If bits is non null, it should have enough size to hold the parameters * size in bits. For RSA the bits returned is the modulus. * For DSA the bits returned are of the public exponent. * * Returns: a member of the #gnutls_pk_algorithm_t enumeration on * success, or a negative error code on error. * * Since: 2.4.0 **/ gnutls_pk_algorithm_t gnutls_openpgp_privkey_get_subkey_pk_algorithm(gnutls_openpgp_privkey_t key, unsigned int idx, unsigned int *bits) { cdk_packet_t pkt; int algo; if (!key) { gnutls_assert(); return GNUTLS_PK_UNKNOWN; } if (idx == GNUTLS_OPENPGP_MASTER_KEYID_IDX) return gnutls_openpgp_privkey_get_pk_algorithm(key, bits); pkt = _get_secret_subkey(key, idx); algo = 0; if (pkt) { if (bits) *bits = cdk_pk_get_nbits(pkt->pkt.secret_key->pk); algo = pkt->pkt.secret_key->pubkey_algo; if (is_RSA(algo)) algo = GNUTLS_PK_RSA; else if (is_DSA(algo)) algo = GNUTLS_PK_DSA; else algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM; } return algo; }
/** * gnutls_openpgp_key_get_pk_algorithm - This function returns the key's PublicKey algorithm * @key: is an OpenPGP key * @bits: if bits is non null it will hold the size of the parameters' in bits * * This function will return the public key algorithm of an OpenPGP * certificate. * * If bits is non null, it should have enough size to hold the parameters * size in bits. For RSA the bits returned is the modulus. * For DSA the bits returned are of the public exponent. * * Returns a member of the GNUTLS_PKAlgorithm enumeration on success, * or a negative value on error. * **/ int gnutls_openpgp_key_get_pk_algorithm (gnutls_openpgp_key_t key, unsigned int *bits) { cdk_packet_t pkt; int algo = 0; if (!key) return GNUTLS_E_INVALID_REQUEST; pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY); if (pkt && pkt->pkttype == CDK_PKT_PUBLIC_KEY) { if (bits) *bits = cdk_pk_get_nbits (pkt->pkt.public_key); algo = pkt->pkt.public_key->pubkey_algo; if (is_RSA (algo)) algo = GNUTLS_PK_RSA; else if (is_DSA (algo)) algo = GNUTLS_PK_DSA; else algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM; } return algo; }
static cdk_error_t sig_to_sexp (gcry_sexp_t *r_sig_sexp, cdk_pkt_signature_t sig) { gcry_error_t err; cdk_error_t rc; const char *fmt; if (!r_sig_sexp || !sig) return CDK_Inv_Value; if (is_ELG (sig->pubkey_algo)) return CDK_Not_Implemented; rc = 0; if (is_RSA (sig->pubkey_algo)) { fmt = "(sig-val(openpgp-rsa(s%m)))"; err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0]); if (err) rc = map_gcry_error (err); } else if (is_DSA (sig->pubkey_algo)) { fmt = "(sig-val(openpgp-dsa(r%m)(s%m)))"; err = gcry_sexp_build (r_sig_sexp, NULL, fmt, sig->mpi[0], sig->mpi[1]); if (err) rc = map_gcry_error (err); } else rc = CDK_Inv_Algo; return rc; }
/** * cdk_keygen_start: kick off the key generation * @hd: the keygen object * **/ cdk_error_t cdk_keygen_start( cdk_keygen_ctx_t hd ) { gcry_sexp_t s_params = NULL, s_key = NULL; size_t n; int rc = 0; if( !hd || !hd->user_id ) return CDK_Inv_Value; if( is_ELG( hd->key[0].algo ) ) return CDK_Inv_Mode; if( !hd->key[0].len ) hd->key[0].len = 1024; n = hd->key[0].len; if( !hd->sym_prefs ) cdk_keygen_set_prefs( hd, CDK_PREFTYPE_SYM, NULL, 0 ); if( !hd->hash_prefs ) cdk_keygen_set_prefs( hd, CDK_PREFTYPE_HASH, NULL, 0 ); if( !hd->zip_prefs ) cdk_keygen_set_prefs( hd, CDK_PREFTYPE_ZIP, NULL, 0 ); if( is_DSA( hd->key[0].algo ) ) rc = gcry_sexp_build( &s_params, NULL, "(genkey(dsa(nbits %d)))", n ); else if( is_RSA( hd->key[0].algo ) ) rc = gcry_sexp_build( &s_params, NULL, "(genkey(rsa(nbits %d)))", n ); else rc = CDK_Inv_Algo; if( !rc ) rc = gcry_pk_genkey( &s_key, s_params ); gcry_sexp_release( s_params ); if( !rc ) { if( is_DSA( hd->key[0].algo ) ) rc = read_dsa_key( s_key, hd->key[0].resarr ); else if( is_RSA( hd->key[0].algo ) ) rc = read_rsa_key( s_key, hd->key[0].resarr ); hd->key[0].n = cdk_pk_get_npkey( hd->key[0].algo ); } gcry_sexp_release( s_key ); if( !rc ) { if( hd->key[1].algo && hd->key[1].len ) rc = generate_subkey( hd ); } return rc; }
/** * cdk_pk_get_nbits: * @algo: the public key algorithm * * Return the number of MPIs a signature consists of. **/ int cdk_pk_get_nsig(int algo) { if (is_RSA(algo)) return 1; else if (is_DSA(algo)) return 2; else return 0; }
/** * cdk_pk_get_npkey: * @algo: The public key algorithm. * * Return the number of multiprecison integer forming an public * key with the given algorithm. */ int cdk_pk_get_npkey(int algo) { if (is_RSA(algo)) return RSA_PUBLIC_PARAMS; else if (is_DSA(algo)) return DSA_PUBLIC_PARAMS; else if (is_ELG(algo)) return 3; else { gnutls_assert(); return 0; } }
int _gnutls_openpgp_get_algo(int cdk_algo) { int algo; if (is_RSA(cdk_algo)) algo = GNUTLS_PK_RSA; else if (is_DSA(cdk_algo)) algo = GNUTLS_PK_DSA; else { _gnutls_debug_log("Unknown OpenPGP algorithm %d\n", cdk_algo); algo = GNUTLS_PK_UNKNOWN; } return algo; }
/** * cdk_pk_get_nskey: * @algo: the public key algorithm * * Return the number of multiprecision integers forming an * secret key with the given algorithm. **/ int cdk_pk_get_nskey(int algo) { int ret; if (is_RSA(algo)) ret = RSA_PRIVATE_PARAMS - 2; /* we don't have exp1 and exp2 */ else if (is_DSA(algo)) ret = DSA_PRIVATE_PARAMS; else if (is_ELG(algo)) ret = 4; else { gnutls_assert(); return 0; } ret -= cdk_pk_get_npkey(algo); return ret; }
static int xml_add_key_mpi (gnutls_string * xmlkey, cdk_pkt_pubkey_t pk) { const char *s = " <KEY ENCODING=\"HEX\"/>\n"; int rc = 0; if (!xmlkey || !pk) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } _gnutls_string_append_str (xmlkey, s); if (is_RSA (pk->pubkey_algo)) { rc = xml_add_mpi (xmlkey, pk, 0, "RSA-N"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 1, "RSA-E"); } else if (is_DSA (pk->pubkey_algo)) { rc = xml_add_mpi (xmlkey, pk, 0, "DSA-P"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 1, "DSA-Q"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 2, "DSA-G"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 3, "DSA-Y"); } else if (is_ELG (pk->pubkey_algo)) { rc = xml_add_mpi (xmlkey, pk, 0, "ELG-P"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 1, "ELG-G"); if (!rc) rc = xml_add_mpi (xmlkey, pk, 2, "ELG-Y"); } else return GNUTLS_E_UNWANTED_ALGORITHM; return 0; }
/* Convert the given secret key into a gcrypt SEXP object. */ static int seckey_to_sexp (gcry_sexp_t *r_skey, cdk_seckey_t sk) { gcry_sexp_t sexp = NULL; gcry_mpi_t *mpk = NULL, *msk = NULL; gcry_error_t err; cdk_pubkey_t pk; const char *fmt; if (!r_skey || !sk || !sk->pk) return CDK_Inv_Value; pk = sk->pk; mpk = pk->mpi; msk = sk->mpi; *r_skey = NULL; if (is_RSA (sk->pubkey_algo)) { fmt = "(private-key(openpgp-rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))"; err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1], msk[0], msk[1], msk[2], msk[3]); } else if (is_ELG (sk->pubkey_algo)) { fmt = "(private-key(openpgp-elg(p%m)(g%m)(y%m)(x%m)))"; err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1], mpk[2], msk[0]); } else if (is_DSA (sk->pubkey_algo)) { fmt = "(private-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)(x%m)))"; err = gcry_sexp_build (&sexp, NULL, fmt, mpk[0], mpk[1], mpk[2], mpk[3], msk[0]); } else return CDK_Inv_Algo; if (err) return map_gcry_error (err); *r_skey = sexp; return 0; }
/* Encode the given digest into a pkcs#1 compatible format. */ cdk_error_t _cdk_digest_encode_pkcs1 (byte ** r_md, size_t * r_mdlen, int pk_algo, const byte * md, int digest_algo, unsigned nbits) { size_t dlen; if (!md || !r_md || !r_mdlen) return CDK_Inv_Value; dlen = _gnutls_hash_get_algo_len (digest_algo); if (dlen <= 0) return CDK_Inv_Algo; if (is_DSA (pk_algo)) { /* DSS does not use a special encoding. */ *r_md = cdk_malloc (dlen + 1); if (!*r_md) return CDK_Out_Of_Core; *r_mdlen = dlen; memcpy (*r_md, md, dlen); return 0; } else { const byte *asn; int asnlen; cdk_error_t rc; asnlen = _gnutls_get_digest_oid (digest_algo, &asn); if (asnlen < 0) return asnlen; rc = do_encode_md (r_md, r_mdlen, md, digest_algo, dlen, nbits, asn, asnlen); return rc; } return 0; }
/* Convert the given public key to a gcrypt SEXP object. */ static cdk_error_t pubkey_to_sexp (gcry_sexp_t *r_key_sexp, cdk_pubkey_t pk) { gcry_mpi_t *m; gcry_error_t err; const char *fmt = NULL; cdk_error_t rc = 0; if (!r_key_sexp || !pk) return CDK_Inv_Value; m = pk->mpi; if (is_RSA (pk->pubkey_algo)) { fmt = "(public-key(openpgp-rsa(n%m)(e%m)))"; err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1]); if (err) rc = map_gcry_error (err); } else if (is_ELG (pk->pubkey_algo)) { fmt = "(public-key(openpgp-elg(p%m)(g%m)(y%m)))"; err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2]); if (err) rc = map_gcry_error (err); } else if (is_DSA (pk->pubkey_algo)) { fmt = "(public-key(openpgp-dsa(p%m)(q%m)(g%m)(y%m)))"; err = gcry_sexp_build (r_key_sexp, NULL, fmt, m[0], m[1], m[2], m[3]); if (err) rc = map_gcry_error (err); } else rc = CDK_Inv_Algo; return rc; }
static int xml_add_key (gnutls_string * xmlkey, int ext, cdk_pkt_pubkey_t pk, int sub) { const char *algo, *s; char keyid[16], fpr[41], tmp[32]; uint8_t fingerpr[20]; unsigned int kid[2]; int i = 0, rc = 0; if (!xmlkey || !pk) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } s = sub ? " <SUBKEY>\n" : " <MAINKEY>\n"; _gnutls_string_append_str (xmlkey, s); cdk_pk_get_keyid (pk, kid); snprintf (keyid, 16, "%08lX%08lX", kid[0], kid[1]); rc = xml_add_tag (xmlkey, "KEYID", keyid); if (rc) return rc; cdk_pk_get_fingerprint (pk, fingerpr); for (i = 0; i < 20; i++) sprintf (fpr + 2 * i, "%02X", fingerpr[i]); fpr[40] = '\0'; rc = xml_add_tag (xmlkey, "FINGERPRINT", fpr); if (rc) return rc; if (is_DSA (pk->pubkey_algo)) algo = "DSA"; else if (is_RSA (pk->pubkey_algo)) algo = "RSA"; else if (is_ELG (pk->pubkey_algo)) algo = "ELG"; else algo = "???"; rc = xml_add_tag (xmlkey, "PKALGO", algo); if (rc) return rc; sprintf (tmp, "%d", cdk_pk_get_nbits (pk)); rc = xml_add_tag (xmlkey, "KEYLEN", tmp); if (rc) return rc; sprintf (tmp, "%lu", pk->timestamp); rc = xml_add_tag (xmlkey, "CREATED", tmp); if (rc) return rc; if (pk->expiredate > 0) { sprintf (tmp, "%lu", (unsigned long) pk->expiredate); rc = xml_add_tag (xmlkey, "EXPIREDATE", tmp); if (rc) return rc; } sprintf (tmp, "%d", pk->is_revoked); rc = xml_add_tag (xmlkey, "REVOKED", tmp); if (rc) return rc; if (ext) { rc = xml_add_key_mpi (xmlkey, pk); if (rc) return rc; } s = sub ? " </SUBKEY>\n" : " </MAINKEY>\n"; _gnutls_string_append_str (xmlkey, s); return 0; }
/** * cdk_pk_verify: * @pk: the public key * @sig: signature * @md: the message digest * * Verify the signature in @sig and compare it with the message digest in @md. **/ cdk_error_t cdk_pk_verify (cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) { gnutls_datum_t s_sig; byte *encmd = NULL; size_t enclen; cdk_error_t rc; int ret, algo; unsigned int i; gnutls_datum_t data; gnutls_pk_params_st params; if (!pk || !sig || !md) { gnutls_assert (); return CDK_Inv_Value; } if (is_DSA (pk->pubkey_algo)) algo = GNUTLS_PK_DSA; else if (is_RSA (pk->pubkey_algo)) algo = GNUTLS_PK_RSA; else { gnutls_assert (); return CDK_Inv_Value; } rc = sig_to_datum (&s_sig, sig); if (rc) { gnutls_assert (); goto leave; } rc = _cdk_digest_encode_pkcs1 (&encmd, &enclen, pk->pubkey_algo, md, sig->digest_algo, cdk_pk_get_nbits (pk)); if (rc) { gnutls_assert (); goto leave; } data.data = encmd; data.size = enclen; params.params_nr = cdk_pk_get_npkey (pk->pubkey_algo); for (i = 0; i < params.params_nr; i++) params.params[i] = pk->mpi[i]; params.flags = 0; ret = _gnutls_pk_verify (algo, &data, &s_sig, ¶ms); if (ret < 0) { gnutls_assert (); rc = map_gnutls_error (ret); goto leave; } rc = 0; leave: _gnutls_free_datum (&s_sig); cdk_free (encmd); return rc; }
/** * cdk_pk_verify: * @pk: the public key * @sig: signature * @md: the message digest * * Verify the signature in @sig and compare it with the message digest in @md. **/ cdk_error_t cdk_pk_verify(cdk_pubkey_t pk, cdk_pkt_signature_t sig, const byte * md) { gnutls_datum_t s_sig = { NULL, 0 }, di = { NULL, 0}; byte *encmd = NULL; cdk_error_t rc; int ret, algo; unsigned int i; gnutls_pk_params_st params; const mac_entry_st *me; if (!pk || !sig || !md) { gnutls_assert(); return CDK_Inv_Value; } if (is_DSA(pk->pubkey_algo)) algo = GNUTLS_PK_DSA; else if (is_RSA(pk->pubkey_algo)) algo = GNUTLS_PK_RSA; else { gnutls_assert(); return CDK_Inv_Value; } rc = sig_to_datum(&s_sig, sig); if (rc) { gnutls_assert(); goto leave; } me = mac_to_entry(sig->digest_algo); rc = _gnutls_set_datum(&di, md, _gnutls_hash_get_algo_len(me)); if (rc < 0) { rc = gnutls_assert_val(CDK_Out_Of_Core); goto leave; } rc = pk_prepare_hash(algo, me, &di); if (rc < 0) { rc = gnutls_assert_val(CDK_General_Error); goto leave; } params.params_nr = cdk_pk_get_npkey(pk->pubkey_algo); for (i = 0; i < params.params_nr; i++) params.params[i] = pk->mpi[i]; params.flags = 0; ret = _gnutls_pk_verify(algo, &di, &s_sig, ¶ms); if (ret < 0) { gnutls_assert(); rc = map_gnutls_error(ret); goto leave; } rc = 0; leave: _gnutls_free_datum(&s_sig); _gnutls_free_datum(&di); cdk_free(encmd); return rc; }