Marco Donati wrote:
> 
> > The usual way to do this kind of thing is to write your own RSA_METHOD
> > to hand over the signing operation (which will probably be
> > RSA_private_encrypt() ) to the smart card, then place the result in an
> > EVP_PKEY structure.
> > What this ultimately does it calls application supplied functions when
> > the particular key is used. Then you just sign as normal but pass it
> > your smart card EVP_PKEY structure for the private key.
> 
> Excuse me, probably I didn't understand well what you said.
> I have a similar problem.
> 
> Some smartcards receive the data and put them in a PKCS#1 structure before
> signing them (but they put the Sha1 Identifier in the
> DigestAlgorithmIdentifier field)
> This signatures are well verified by Open SSL if I put them into a signed
> PKCS#7 and push a Sha1 algorithm identifier into the algorithms stack.
> 
> Some others smartcards simply encrypt with the private key what you thell
> them to sign.
> I can't verify these signatures with Open-SSL.
> 
> I can't fetch from smartcard the whole private key because the key are
> onboard generated and only the modulus and public exponent (that is, the
> public key) are extractable (so how can i put my smartcard private key into
> an EVP_PKEY?)
> 
> How can put these raw raw signatures in a PKCS#7?
> 
> How can i verify smartcard signatures with algorithms other than Sha1?
> 

Ah let me explain a bit further. This is a rather complex topic but what
you are asking can and has been done using OpenSSL.

If you start with the RSA structure:

struct rsa_st
        {
        /* The first parameter is used to pickup errors where
         * this is passed instead of aEVP_PKEY, it is set to 0 */
        int pad;
        int version;
        RSA_METHOD *meth;
        BIGNUM *n;
        BIGNUM *e;
        BIGNUM *d;
        BIGNUM *p;
        BIGNUM *q;
        BIGNUM *dmp1;
        BIGNUM *dmq1;
        BIGNUM *iqmp;
        /* be careful using this if the RSA structure is shared */
        CRYPTO_EX_DATA ex_data;
        int references;
        int flags;

        /* Used to cache montgomery values */
        BN_MONT_CTX *_method_mod_n;
        BN_MONT_CTX *_method_mod_p;
        BN_MONT_CTX *_method_mod_q;

        /* all BIGNUM values are actually in the following data, if it is not
         * NULL */
        char *bignum_data;
        BN_BLINDING *blinding;
        };

Now with a normal RSA key n,e,d,p,q,dmp1,dmq1 and iqmp will all be
filled in. If you use the standard OpenSSL RSA routines then you have to
fill in some private key components because OpenSSL does the necessary
calculations itself.

If however the key is not extractable from some hardware (for example
a smart card) then this is not possible. 

Thats where the RSA_METHOD comes in:

typedef struct rsa_meth_st
        {
        const char *name;
        int (*rsa_pub_enc)(int flen,unsigned char *from,unsigned char *to,
                           RSA *rsa,int padding);
        int (*rsa_pub_dec)(int flen,unsigned char *from,unsigned char *to,
                           RSA *rsa,int padding);
        int (*rsa_priv_enc)(int flen,unsigned char *from,unsigned char *to,
                            RSA *rsa,int padding);
        int (*rsa_priv_dec)(int flen,unsigned char *from,unsigned char *to,
                            RSA *rsa,int padding);
        int (*rsa_mod_exp)(BIGNUM *r0,BIGNUM *I,RSA *rsa); /* Can be null */
        int (*bn_mod_exp)(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
                          const BIGNUM *m, BN_CTX *ctx,
                          BN_MONT_CTX *m_ctx); /* Can be null */
        int (*init)(RSA *rsa);          /* called at new */
        int (*finish)(RSA *rsa);        /* called at free */
        int flags;                      /* RSA_METHOD_FLAG_* things */
        char *app_data;                 /* may be needed! */
/* New sign and verify functions: some libraries don't allow arbitrary
data
 * to be signed/verified: this allows them to be used. Note: for this to
work
 * the RSA_public_decrypt() and RSA_private_encrypt() should *NOT* be
used
 * RSA_sign(), RSA_verify() should be used instead. Note: for backwards
 * compatibility this functionality is only enabled if the
RSA_FLAG_SIGN_VER
 * option is set in 'flags'.
 */
        int (*rsa_sign)(int type, unsigned char *m, unsigned int m_len,
             unsigned char *sigret, unsigned int *siglen, RSA *rsa);
        int (*rsa_verify)(int dtype, unsigned char *m, unsigned int m_len,
             unsigned char *sigbuf, unsigned int siglen, RSA *rsa);

        } RSA_METHOD;

These are a bunch of callback which are used to do the actual RSA
operations. By default these are set to perform the low level
calculations on the key components. 

However you can create your own RSA_METHOD and supply some (or all)
of the low level functionality and change your keys RSA_METHOD.

Now for smart cards you typically just perform private key operations
on the card and have OpenSSL handle the public key operations. In order
to handle public key operations you need to fill in the public key
components in the RSA structure (n, e) but you can get those from the
certificate on the smart card or by some other means.

Which callbacks you replace depends on what functionality is available.

If you are using a smart card that fills in the DigestInfo structure
itself then you are probably best using the rsa_sign() function.

If the card takes a DigestInfo structure and does its own PKCS#1 block
padding then rsa_priv_enc() and rsa_priv_dec() (for key exchange) is
most suitable.

However in many cases you pass a "raw" block to sign and the card
inrernally does raw^d mod n or equivalent.

This is where the rsa_mod_exp() and bn_mod_exp() callbacks are
useful. These normally perform the primitive RSA operations based
in key components.

In particular rsa_mod_exp() is used for the low level private 
key operation, by default it does the equivalent of:

r0 = I ^ d mod n

What you need to do then is to write your own version of this 
callback and have it convert the 'I' component to raw form, send it 
to the card then convert the result to a bignum which is places in 'r0'.

So what you have is an RSA structure containing an an RSA_METHOD 
structure with some of your own callbacks in it. You then embed this
in an EVP_PKEY structure.

Now this EVP_PKEY structure will behave almost identically to a normal
EVP_PKEY structure and in almost all cases you just pass it to the
required function and it will do the rest.

As I said this is a complex topic and I've only given a rough outline
of what you need to do. The flags field for example needs to be set
appropriately and you can also store application specific data using
the ex_data functions (for example some kind of identifier with the
private key to use).

For more details check the stuff in crypto/rsa/rsa_eay.c and of course
the RSA manual pages, which don't currently cover RSA_METHOD in much
detail.

Steve.
-- 
Dr Stephen N. Henson.   http://www.drh-consultancy.demon.co.uk/
Personal Email: [EMAIL PROTECTED] 
Senior crypto engineer, Celo Communications: http://www.celocom.com/
Core developer of the   OpenSSL project: http://www.openssl.org/
Business Email: [EMAIL PROTECTED] PGP key: via homepage.

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to