aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-openpgp.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/app-openpgp.c')
-rw-r--r--scd/app-openpgp.c61
1 files changed, 47 insertions, 14 deletions
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index dc775f77e..c17452555 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -2061,6 +2061,9 @@ get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining)
return result;
}
+#define KDF_DATA_LENGTH_MIN 90
+#define KDF_DATA_LENGTH_MAX 110
+
/* Compute hash if KDF-DO is available. CHVNO must be 0 for reset
code, 1 or 2 for user pin and 3 for admin pin.
*/
@@ -2068,21 +2071,33 @@ static gpg_error_t
pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
{
gpg_error_t err = 0;
- void *relptr;
+ void *relptr = NULL;
unsigned char *buffer;
size_t buflen;
if (app->app_local->extcap.kdf_do
&& (relptr = get_one_do (app, 0x00F9, &buffer, &buflen, NULL))
- && buflen == 110 && (buffer[2] == 0x03))
+ && buflen >= KDF_DATA_LENGTH_MIN && (buffer[2] == 0x03))
{
- char *salt;
+ const char *salt;
unsigned long s2k_count;
char dek[32];
+ int salt_index;
- salt = &buffer[(chvno==3 ? 34 : (chvno==0 ? 24 : 14))];
s2k_count = (((unsigned int)buffer[8] << 24)
| (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]);
+
+ if (buflen == KDF_DATA_LENGTH_MIN)
+ salt_index =14;
+ else if (buflen == KDF_DATA_LENGTH_MAX)
+ salt_index = (chvno==3 ? 34 : (chvno==0 ? 24 : 14));
+ else
+ {
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+
+ salt = &buffer[salt_index];
err = gcry_kdf_derive (pinvalue, strlen (pinvalue),
GCRY_KDF_ITERSALTED_S2K,
DIGEST_ALGO_SHA256, salt, 8,
@@ -2094,12 +2109,12 @@ pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
memcpy (pinvalue, dek, *r_pinlen);
wipememory (dek, *r_pinlen);
}
-
- xfree (relptr);
- }
+ }
else
*r_pinlen = strlen (pinvalue);
+ leave:
+ xfree (relptr);
return err;
}
@@ -2444,7 +2459,7 @@ do_setattr (app_t app, const char *name,
{ "SM-KEY-MAC", 0x00D2, 3, 0, 1 },
{ "KEY-ATTR", 0, 0, 3, 1 },
{ "AESKEY", 0x00D5, 3, 0, 1 },
- { "KDF", 0x00F9, 3, 0, 1 },
+ { "KDF", 0x00F9, 3, 4, 1 },
{ NULL, 0 }
};
int exmode;
@@ -2492,6 +2507,12 @@ do_setattr (app_t app, const char *name,
app->force_chv1 = (valuelen && *value == 0);
else if (table[idx].special == 2)
parse_login_data (app);
+ else if (table[idx].special == 4)
+ {
+ app->did_chv1 = 0;
+ app->did_chv2 = 0;
+ app->did_chv3 = 0;
+ }
return rc;
}
@@ -3208,21 +3229,33 @@ change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
relptr = get_one_do (app, 0xC1+keyno, &buf, &buflen, NULL);
if (!relptr)
err = gpg_error (GPG_ERR_CARD);
- else if (buflen < 6 || buf[0] != PUBKEY_ALGO_RSA)
+ else if (buflen < 6)
{
- /* Attriutes too short or not an RSA key. */
+ /* Attributes too short. */
xfree (relptr);
err = gpg_error (GPG_ERR_CARD);
}
else
{
- /* We only change n_bits and don't touch anything else. Before we
- do so, we round up NBITS to a sensible way in the same way as
- gpg's key generation does it. This may help to sort out problems
- with a few bits too short keys. */
+ /* If key attribute was RSA, we only change n_bits and don't
+ touch anything else. Before we do so, we round up NBITS to a
+ sensible way in the same way as gpg's key generation does it.
+ This may help to sort out problems with a few bits too short
+ keys. */
nbits = ((nbits + 31) / 32) * 32;
buf[1] = (nbits >> 8);
buf[2] = nbits;
+
+ /* If it was not RSA, we need to fill other parts. */
+ if (buf[0] != PUBKEY_ALGO_RSA)
+ {
+ buf[0] = PUBKEY_ALGO_RSA;
+ buf[3] = 0;
+ buf[4] = 32;
+ buf[5] = 0;
+ buflen = 6;
+ }
+
err = change_keyattr (app, keyno, buf, buflen, pincb, pincb_arg);
xfree (relptr);
}