[ssh_x509] DSA patch
ssh_x509 at roumenpetrov.info
ssh_x509 at roumenpetrov.info
Mon Feb 4 14:47:06 EET 2013
thanks - that works fine with my tests. andrew
On Sat, Feb 02, 2013 at 04:31:07PM +0200, SSH X509 wrote:
> Hi Andrew,
>
>
> ssh_x509 at roumenpetrov.info wrote:
> >Hi,
> >
> >This isn't the greatest code - it's badly indented (sorry), poorly tested, and
> >the error handling may be incomplete - but it extends the PKCS11 code to
> >handle DSA keys as well as RSA (see the "FIXME" comment in your ssh-pkcs11.c).
> Thanks for contribution.
>
> Indentation is perfect , just copy&paste from email. You fully follow coding style.
>
> Please find attached "0001-support-DSA-in-PKCS-11-wrapper.patch"
> with integrated code with following updates:
> - use openssl define SHA_DIGEST_LENGTH
> - use DSA_SIG_new() instead malloc
> - fprintf(stderr... replaced with debug3(...
> - x509key_from_blob return NULL instead to raise fatal if algorithm is not supported
>
>
> >I, my employer, and our client waive all rights to this code, but provide no
> >warranty or guarantees to its safety, correctness or usefulness. Feel free to
> >include it in your patches if it helps.
> What to add in Copyright section of ssh-pkcs11.c ?
>
> >Cheers + thanks for the work,
> >Andrew
>
> Roumen
>
> >From d281131f29c3ece7bc6978d77c849e91b17be719 Mon Sep 17 00:00:00 2001
> From: Roumen Petrov <openssh at roumenpetrov.info>
> Date: Sat, 2 Feb 2013 16:07:18 +0200
> Subject: [PATCH] support DSA in PKCS#11 wrapper
>
> ---
> ssh-pkcs11.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> ssh-x509.c | 3 +-
> 2 files changed, 186 insertions(+), 4 deletions(-)
>
> diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
> index b6c9c44..a8804ee 100644
> --- a/ssh-pkcs11.c
> +++ b/ssh-pkcs11.c
> @@ -2,6 +2,7 @@
> /*
> * Copyright (c) 2010 Markus Friedl. All rights reserved.
> * Copyright (c) 2011 Kenneth Robinette. All rights reserved.
> + * Copyright (c) 2013 (TODO Andrew ?). All rights reserved.
> *
> * Permission to use, copy, modify, and distribute this software for any
> * purpose with or without fee is hereby granted, provided that the above
> @@ -48,6 +49,12 @@
> #include "ssh-x509.h"
> #endif
>
> +/* Define DSA_{set|get}_app_data for compatibility with
> + * RSA code. Note ..._ex_... methods are preferred
> + */
> +#define DSA_set_app_data(s,arg) DSA_set_ex_data(s,0,arg)
> +#define DSA_get_app_data(s) DSA_get_ex_data(s,0)
> +
> struct pkcs11_slotinfo {
> CK_TOKEN_INFO token;
> CK_SESSION_HANDLE session;
> @@ -74,6 +81,9 @@ struct pkcs11_key {
> CK_ULONG slotidx;
> int (*orig_finish)(RSA *rsa);
> RSA_METHOD rsa_method;
> + /* RSA&DSA must be union */
> + int (*orig_dsa_finish)(DSA *rsa);
> + DSA_METHOD dsa_method;
> char *keyid;
> int keyid_len;
> };
> @@ -195,6 +205,25 @@ pkcs11_rsa_finish(RSA *rsa)
> return (rv);
> }
>
> +/* openssl callback for freeing an DSA key */
> +static int
> +pkcs11_dsa_finish(DSA *dsa)
> +{
> + struct pkcs11_key *k11;
> + int rv = -1;
> +
> + if ((k11 = DSA_get_app_data(dsa)) != NULL) {
> + if (k11->orig_dsa_finish)
> + rv = k11->orig_dsa_finish(dsa);
> + if (k11->provider)
> + pkcs11_provider_unref(k11->provider);
> + if (k11->keyid)
> + xfree(k11->keyid);
> + xfree(k11);
> + }
> + return (rv);
> +}
> +
> /* find a single 'obj' for given attributes */
> static int
> pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
> @@ -335,6 +364,141 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
> return (0);
> }
>
> +/* redirect private key operations for dsa key to pkcs11 token */
> +static DSA_SIG*
> +pkcs11_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
> +{
> + struct pkcs11_key *k11;
> + struct pkcs11_slotinfo *si;
> + CK_FUNCTION_LIST *f;
> + CK_OBJECT_HANDLE obj;
> + CK_ULONG tlen = 0;
> + CK_RV rv;
> + CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY;
> + CK_BBOOL true_val = CK_TRUE;
> + CK_MECHANISM mech = {
> + CKM_RSA_PKCS, NULL_PTR, 0
> + };
> + CK_ATTRIBUTE key_filter[] = {
> + {CKA_CLASS, NULL, sizeof(private_key_class) },
> + {CKA_ID, NULL, 0},
> + {CKA_SIGN, NULL, sizeof(true_val) }
> + };
> + char *pin, prompt[1024];
> + DSA_SIG *sig = NULL;
> +
> + debug3("pkcs11_dsa_do_sign");
> +
> + /* some compilers complain about non-constant initializer so we
> + use NULL in CK_ATTRIBUTE above and set the values here */
> + key_filter[0].pValue = &private_key_class;
> + key_filter[2].pValue = &true_val;
> +
> + if ((k11 = DSA_get_app_data(dsa)) == NULL) {
> + error("DSA_get_app_data failed for dsa %p", (void*)dsa);
> + return NULL;
> + }
> + if (!k11->provider || !k11->provider->valid) {
> + error("no pkcs11 (valid) provider for dsa %p", (void*)dsa);
> + return NULL;
> + }
> + f = k11->provider->function_list;
> + si = &k11->provider->slotinfo[k11->slotidx];
> + if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
> + if (!pkcs11_interactive) {
> + error("need pin");
> + return (NULL);
> + }
> + snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
> + si->token.label);
> + pin = read_passphrase(prompt, RP_ALLOW_EOF);
> + if (pin == NULL)
> + return (NULL); /* bail out */
> + if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin)))
> + != CKR_OK) {
> + xfree(pin);
> + error("C_Login failed: %lu", rv);
> + return (NULL);
> + }
> + xfree(pin);
> + si->logged_in = 1;
> + }
> + key_filter[1].pValue = k11->keyid;
> + key_filter[1].ulValueLen = k11->keyid_len;
> + /* try to find object w/CKA_SIGN first, retry w/o */
> + if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
> + pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
> + error("cannot find private key");
> + } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
> + error("C_SignInit failed: %lu", rv);
> + } else {
> + char rs[(2*SHA_DIGEST_LENGTH)];
> + tlen = (2*SHA_DIGEST_LENGTH);
> + rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dlen, rs, &tlen);
> + if (rv == CKR_OK) {
> + sig = DSA_SIG_new();
> + if (sig == NULL) {
> + /*out of memory*/
> + goto done;
> + }
> + sig->r = BN_bin2bn(rs, SHA_DIGEST_LENGTH, NULL);
> + sig->s = BN_bin2bn(rs + SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH, NULL);
> + }
> + else
> + error("C_Sign failed: %lu", rv);
> + }
> +done:
> + return (sig);
> +}
> +
> +static int
> +pkcs11_dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) {
> + (void)dsa;
> + (void)ctx_in;
> + (void)kinvp;
> + (void)rp;
> + debug3("pkcs11_dsa_sign_setup");
> + return (-1);
> +}
> +
> +static int
> +pkcs11_dsa_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig, DSA *dsa) {
> + (void)dgst;
> + (void)dgst_len;
> + (void)sig;
> + (void)dsa;
> + debug3("pkcs11_dsa_do_verify");
> + return (-1);
> +}
> +
> +
> +static int
> +pkcs11_dsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
> + CK_ATTRIBUTE *keyid_attrib, DSA *dsa)
> +{
> + struct pkcs11_key *k11;
> + const DSA_METHOD *def = DSA_get_default_method();
> +
> + k11 = xcalloc(1, sizeof(*k11));
> + k11->provider = provider;
> + provider->refcount++; /* provider referenced by DSA key */
> + k11->slotidx = slotidx;
> + /* identify key object on smartcard */
> + k11->keyid_len = keyid_attrib->ulValueLen;
> + k11->keyid = xmalloc(k11->keyid_len);
> + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
> + k11->orig_dsa_finish = def->finish;
> + memcpy(&k11->dsa_method, def, sizeof(k11->dsa_method));
> + k11->dsa_method.name = "pkcs11";
> + k11->dsa_method.dsa_sign_setup = pkcs11_dsa_sign_setup;
> + k11->dsa_method.dsa_do_sign = pkcs11_dsa_do_sign;
> + k11->dsa_method.dsa_do_verify = pkcs11_dsa_do_verify;
> + k11->dsa_method.finish = pkcs11_dsa_finish;
> + DSA_set_method(dsa, &k11->dsa_method);
> + DSA_set_app_data(dsa, k11);
> + return (0);
> +}
> +
> /* remove trailing spaces */
> static void
> rmspace(char *buf, size_t len)
> @@ -510,9 +674,28 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp,
> if ((rv = f->C_GetAttributeValue(session,obj, attribs, 3)) != CKR_OK)
> error("C_GetAttributeValue failed: %lu",rv);
> else {
> + int rv_wrap;
> key = x509key_from_blob(attribs[1].pValue, attribs[1].ulValueLen);
> - /* FIXME non-rsa keys */
> - if (key && pkcs11_rsa_wrap(p, slotidx, &attribs[0], key->rsa) == 0) {
> + if (key == NULL) {
> + /* x509key_from_blob return NULL if key type is not
> + * supported and if can not extract X.509 certificate
> + */
> + debug3("%s: x509key_from_blob fail", __func__);
> + continue;
> + }
> +
> + switch(X509KEY_BASETYPE(key)) {
> + case KEY_RSA:
> + rv_wrap = pkcs11_rsa_wrap(p, slotidx, &attribs[0], key->rsa);
> + break;
> + case KEY_DSA:
> + rv_wrap = pkcs11_dsa_wrap(p, slotidx, &attribs[0], key->dsa);
> + break;
> + default:
> + rv_wrap = -1;
> + }
> +
> + if (rv_wrap == 0) {
> key->flags |= KEY_FLAG_EXT;
> /* expand key array and add key */
> *keysp = xrealloc(*keysp, *nkeys + 1, sizeof(Key *));
> diff --git a/ssh-x509.c b/ssh-x509.c
> index 1cab651..c060872 100644
> --- a/ssh-x509.c
> +++ b/ssh-x509.c
> @@ -660,8 +660,7 @@ x509_to_key(X509 *x509) {
> break;
>
> default:
> - fatal("%s: unsupported env_pkey->type %d", __func__, env_pkey->type);
> - /*unreachable code*/
> + error("%s: unsupported env_pkey->type %d", __func__, env_pkey->type);
> }
>
> return(key);
> --
> 1.7.12.1
>
>
>
> _______________________________________________
> ssh_x509 mailing list
> ssh_x509 at roumenpetrov.info
> http://roumenpetrov.info/mailman/listinfo/ssh_x509_roumenpetrov.info
More information about the ssh_x509
mailing list