X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/bbe88b6d930d2f3cef8d1c896edaa60fd146e84f..HEAD:/scard-opensc.c diff --git a/scard-opensc.c b/scard-opensc.c index e91bc25b..36dae05f 100644 --- a/scard-opensc.c +++ b/scard-opensc.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2002 Juha Yrjölä. All rights reserved. * Copyright (c) 2001 Markus Friedl. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -26,16 +26,21 @@ #include "includes.h" #if defined(SMARTCARD) && defined(USE_OPENSC) +#include + #include #include +#include +#include + #include #include #include "key.h" #include "log.h" #include "xmalloc.h" -#include "readpass.h" +#include "misc.h" #include "scard.h" #if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE) @@ -81,7 +86,7 @@ sc_close(void) } } -static int +static int sc_init(void) { int r; @@ -89,6 +94,12 @@ sc_init(void) r = sc_establish_context(&ctx, "openssh"); if (r) goto err; + if (sc_reader_id >= ctx->reader_count) { + r = SC_ERROR_NO_READERS_FOUND; + error("Illegal reader number %d (max %d)", sc_reader_id, + ctx->reader_count -1); + goto err; + } r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card); if (r) goto err; @@ -104,7 +115,8 @@ err: /* private key operations */ static int -sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out) +sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out, + unsigned int usage) { int r; struct sc_priv_data *priv; @@ -124,7 +136,8 @@ sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out) goto err; } } - r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj); + r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id, + usage, &key_obj); if (r) { error("Unable to find private key from SmartCard: %s", sc_strerror(r)); @@ -133,7 +146,16 @@ sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out) key = key_obj->data; r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id, &pin_obj); - if (r) { + if (r == SC_ERROR_OBJECT_NOT_FOUND) { + /* no pin required */ + r = sc_lock(card); + if (r) { + error("Unable to lock smartcard: %s", sc_strerror(r)); + goto err; + } + *key_obj_out = key_obj; + return 0; + } else if (r) { error("Unable to find PIN object from SmartCard: %s", sc_strerror(r)); goto err; @@ -161,6 +183,9 @@ err: return -1; } +#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \ + SC_PKCS15_PRKEY_USAGE_UNWRAP + static int sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding) @@ -169,11 +194,12 @@ sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int r; if (padding != RSA_PKCS1_PADDING) - return -1; - r = sc_prkey_op_init(rsa, &key_obj); + return -1; + r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT); if (r) return -1; - r = sc_pkcs15_decipher(p15card, key_obj, 0, from, flen, to, flen); + r = sc_pkcs15_decipher(p15card, key_obj, SC_ALGORITHM_RSA_PAD_PKCS1, + from, flen, to, flen); sc_unlock(card); if (r < 0) { error("sc_pkcs15_decipher() failed: %s", sc_strerror(r)); @@ -185,6 +211,9 @@ err: return -1; } +#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \ + SC_PKCS15_PRKEY_USAGE_SIGNRECOVER + static int sc_sign(int type, u_char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, RSA *rsa) @@ -193,7 +222,15 @@ sc_sign(int type, u_char *m, unsigned int m_len, int r; unsigned long flags = 0; - r = sc_prkey_op_init(rsa, &key_obj); + /* XXX: sc_prkey_op_init will search for a pkcs15 private + * key object with the sign or signrecover usage flag set. + * If the signing key has only the non-repudiation flag set + * the key will be rejected as using a non-repudiation key + * for authentication is not recommended. Note: This does not + * prevent the use of a non-repudiation key for authentication + * if the sign or signrecover flag is set as well. + */ + r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN); if (r) return -1; /* FIXME: length of sigret correct? */ @@ -293,7 +330,7 @@ static void convert_rsa_to_rsa1(Key * in, Key * out) { struct sc_priv_data *priv; - + out->rsa->flags = in->rsa->flags; out->flags = in->flags; RSA_set_method(out->rsa, RSA_get_method(in->rsa)); @@ -305,7 +342,7 @@ convert_rsa_to_rsa1(Key * in, Key * out) return; } -static int +static int sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) { int r; @@ -317,7 +354,7 @@ sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) EVP_PKEY *pubkey = NULL; u8 *p; char *tmp; - + debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]); r = sc_pkcs15_read_certificate(p15card, cinfo, &cert); if (r) { @@ -326,7 +363,7 @@ sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) } x509 = X509_new(); if (x509 == NULL) { - r = -1; + r = -1; goto err; } p = cert->data; @@ -359,7 +396,7 @@ sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); debug("fingerprint %d %s", key_size(k), tmp); xfree(tmp); - + return 0; err: if (cert) @@ -423,9 +460,16 @@ sc_get_keys(const char *id, const char *pin) } key_count = r; } - /* FIXME: only keep entries with a corresponding private key */ - keys = xmalloc(sizeof(Key *) * (key_count*2+1)); + if (key_count > 1024) + fatal("Too many keys (%u), expected <= 1024", key_count); + keys = xcalloc(key_count * 2 + 1, sizeof(Key *)); for (i = 0; i < key_count; i++) { + sc_pkcs15_object_t *tmp_obj = NULL; + cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id; + if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj)) + /* skip the public key (certificate) if no + * corresponding private key is present */ + continue; k = key_new(KEY_RSA); if (k == NULL) break; @@ -459,4 +503,30 @@ sc_put_key(Key *prv, const char *id) return -1; } +char * +sc_get_key_label(Key *key) +{ + int r; + const struct sc_priv_data *priv; + struct sc_pkcs15_object *key_obj; + + priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa); + if (priv == NULL || p15card == NULL) { + logit("SmartCard key not loaded"); + /* internal error => return default label */ + return xstrdup("smartcard key"); + } + r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj); + if (r) { + logit("Unable to find private key from SmartCard: %s", + sc_strerror(r)); + return xstrdup("smartcard key"); + } + if (key_obj == NULL || key_obj->label == NULL) + /* the optional PKCS#15 label does not exists + * => return the default label */ + return xstrdup("smartcard key"); + return xstrdup(key_obj->label); +} + #endif /* SMARTCARD */