diff options
Diffstat (limited to 'agent')
-rw-r--r-- | agent/cvt-openpgp.c | 84 | ||||
-rw-r--r-- | agent/protect.c | 79 |
2 files changed, 116 insertions, 47 deletions
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 58327c668..6ea266628 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -81,9 +81,16 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey, break; case GCRY_PK_ECC: - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)(q%m)))", - curve, pkey[0]); + if (!curve) + err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve %s)(flags eddsa)(q%m)))", + "Ed25519", pkey[0]); + else + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve %s)(q%m)))", + curve, pkey[0]); break; default: @@ -139,6 +146,15 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, case GCRY_PK_ECC: if (!curve) err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + err = gcry_sexp_build (&s_skey, NULL, + "(private-key(ecc(curve%s)(flags eddsa)" + "(q%m)(d%m)))", + "Ed25519", skey[0], skey[1]); + } else err = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", @@ -198,11 +214,24 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey, break; case GCRY_PK_ECC: - err = gcry_sexp_build - (&s_skey, NULL, - "(protected-private-key(ecc(curve%s)(q%m)" - "(protected openpgp-native%S)))", - curve, skey[0], transfer_key); + if (!curve) + err = gpg_error (GPG_ERR_BAD_SECKEY); + else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL))) + { + /* Do not store the OID as name but the real name and the + EdDSA flag. */ + err = gcry_sexp_build + (&s_skey, NULL, + "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)" + "(protected openpgp-native%S)))", + "Ed25519", skey[0], transfer_key); + } + else + err = gcry_sexp_build + (&s_skey, NULL, + "(protected-private-key(ecc(curve%s)(q%m)" + "(protected openpgp-native%S)))", + curve, skey[0], transfer_key); break; default: @@ -373,7 +402,7 @@ do_unprotect (const char *passphrase, if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1)) return gpg_error (GPG_ERR_BAD_SECKEY); - if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_USER1)) + if (gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; const unsigned char *buffer; @@ -1064,15 +1093,36 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey, ndata = 20; /* Space for the SHA-1 checksum. */ for (i = npkey, j = 0; i < nskey; i++, j++ ) { - err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]); - if (err) + if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE)) { - err = gpg_error_from_syserror (); - for (i = 0; i < j; i++) - xfree (bufarr[i]); - return err; + const void *s; + unsigned int n; + + s = gcry_mpi_get_opaque (array[i], &n); + nbits[j] = n; + n = (n+7)/8; + narr[j] = n; + bufarr[j] = gcry_is_secure (s)? xtrymalloc_secure (n):xtrymalloc (n); + if (!bufarr[j]) + { + err = gpg_error_from_syserror (); + for (i = 0; i < j; i++) + xfree (bufarr[i]); + return err; + } + memcpy (bufarr[j], s, n); + } + else + { + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]); + if (err) + { + for (i = 0; i < j; i++) + xfree (bufarr[i]); + return err; + } + nbits[j] = gcry_mpi_get_nbits (array[i]); } - nbits[j] = gcry_mpi_get_nbits (array[i]); ndata += 2 + narr[j]; } @@ -1218,8 +1268,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, assert (iob.len < sizeof iobbuf -1); iobbuf[iob.len] = 0; err = gcry_sexp_build (&curve, NULL, "(curve %s)", iobbuf); - - gcry_log_debugsxp ("at 1", curve); } } else if (!strcmp (name, "ecdsa")) diff --git a/agent/protect.c b/agent/protect.c index 3a0021871..f633d562e 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -42,7 +42,9 @@ #include "cvt-openpgp.h" #include "sexp-parse.h" -#define PROT_CIPHER GCRY_CIPHER_AES +/* The protection mode for encryption. The supported modes for + decryption are listed in agent_unprotect(). */ +#define PROT_CIPHER GCRY_CIPHER_AES128 #define PROT_CIPHER_STRING "aes" #define PROT_CIPHER_KEYLEN (128/8) @@ -632,6 +634,7 @@ do_decryption (const unsigned char *protected, size_t protectedlen, const char *passphrase, const unsigned char *s2ksalt, unsigned long s2kcount, const unsigned char *iv, size_t ivlen, + int prot_cipher, int prot_cipher_keylen, unsigned char **result) { int rc = 0; @@ -640,11 +643,11 @@ do_decryption (const unsigned char *protected, size_t protectedlen, unsigned char *outbuf; size_t reallen; - blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER); + blklen = gcry_cipher_get_algo_blklen (prot_cipher); if (protectedlen < 4 || (protectedlen%blklen)) return gpg_error (GPG_ERR_CORRUPTED_PROTECTION); - rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC, + rc = gcry_cipher_open (&hd, prot_cipher, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE); if (rc) return rc; @@ -657,17 +660,16 @@ do_decryption (const unsigned char *protected, size_t protectedlen, if (!rc) { unsigned char *key; - size_t keylen = PROT_CIPHER_KEYLEN; - key = gcry_malloc_secure (keylen); + key = gcry_malloc_secure (prot_cipher_keylen); if (!key) rc = out_of_core (); else { rc = hash_passphrase (passphrase, GCRY_MD_SHA1, - 3, s2ksalt, s2kcount, key, keylen); + 3, s2ksalt, s2kcount, key, prot_cipher_keylen); if (!rc) - rc = gcry_cipher_setkey (hd, key, keylen); + rc = gcry_cipher_setkey (hd, key, prot_cipher_keylen); xfree (key); } } @@ -860,6 +862,15 @@ agent_unprotect (ctrl_t ctrl, gnupg_isotime_t protected_at, unsigned char **result, size_t *resultlen) { + static struct { + const char *name; /* Name of the protection method. */ + int algo; /* (A zero indicates the "openpgp-native" hack.) */ + int keylen; /* Used key length in bytes. */ + } algotable[] = { + { "openpgp-s2k3-sha1-aes-cbc", GCRY_CIPHER_AES128, (128/8)}, + { "openpgp-s2k3-sha1-aes256-cbc", GCRY_CIPHER_AES256, (256/8)}, + { "openpgp-native", 0, 0 } + }; int rc; const unsigned char *s; const unsigned char *protect_list; @@ -869,6 +880,7 @@ agent_unprotect (ctrl_t ctrl, const unsigned char *s2ksalt; unsigned long s2kcount; const unsigned char *iv; + int prot_cipher, prot_cipher_keylen; const unsigned char *prot_begin; unsigned char *cleartext; unsigned char *final; @@ -959,31 +971,40 @@ agent_unprotect (ctrl_t ctrl, n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); - if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc")) + + /* Lookup the protection algo. */ + prot_cipher = 0; /* (avoid gcc warning) */ + prot_cipher_keylen = 0; /* (avoid gcc warning) */ + for (i= 0; i < DIM (algotable); i++) + if (smatch (&s, n, algotable[i].name)) + { + prot_cipher = algotable[i].algo; + prot_cipher_keylen = algotable[i].keylen; + break; + } + if (i == DIM (algotable)) + return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION); + + if (!prot_cipher) /* This is "openpgp-native". */ { - if (smatch (&s, n, "openpgp-native")) - { - gcry_sexp_t s_prot_begin; + gcry_sexp_t s_prot_begin; - rc = gcry_sexp_sscan (&s_prot_begin, NULL, - prot_begin, - gcry_sexp_canon_len (prot_begin, 0,NULL,NULL)); - if (rc) - return rc; + rc = gcry_sexp_sscan (&s_prot_begin, NULL, + prot_begin, + gcry_sexp_canon_len (prot_begin, 0,NULL,NULL)); + if (rc) + return rc; - rc = convert_from_openpgp_native (ctrl, - s_prot_begin, passphrase, &final); - gcry_sexp_release (s_prot_begin); - if (!rc) - { - *result = final; - *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL); - } - return rc; + rc = convert_from_openpgp_native (ctrl, s_prot_begin, passphrase, &final); + gcry_sexp_release (s_prot_begin); + if (!rc) + { + *result = final; + *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL); } - else - return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION); + return rc; } + if (*s != '(' || s[1] != '(') return gpg_error (GPG_ERR_INV_SEXP); s += 2; @@ -1026,7 +1047,7 @@ agent_unprotect (ctrl_t ctrl, s++; /* skip list end */ n = snext (&s); - if (n != 16) /* Wrong blocksize for IV (we support only aes-128). */ + if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */ return gpg_error (GPG_ERR_CORRUPTED_PROTECTION); iv = s; s += n; @@ -1040,7 +1061,7 @@ agent_unprotect (ctrl_t ctrl, cleartext = NULL; /* Avoid cc warning. */ rc = do_decryption (s, n, passphrase, s2ksalt, s2kcount, - iv, 16, + iv, 16, prot_cipher, prot_cipher_keylen, &cleartext); if (rc) return rc; |