[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