Hi,

>  CMS_verify() works fine if you have the signer cert, but now we have
>  a CMS file for which only the (trusted) signer public key is available.
>
>  Q: is there a high level function like CMS_verify() that works with a
>  public key?
>
>  If not: what would be the best alternative for us?
>  - Rewrite the CMS_verify() function to use public keys?
>  - Create a cert (with fake signature) with the public key?

In case someone should have to do the same: below is the code
to make a fake cert (if only 1 signerInfo is present).
After that you can call CMS_Verify() with flags = CMS_NO_SIGNER_CERT_VERIFY.

There's another catch: CMS_verify() changes the CMS_ContentInfo struct
in the sense the signer cert is added if it's not already present,
so subsequence CMS_verify() calls will keep using the added cert.
Don't know if that's intentional, but in our case, where we read
candidate certs/pubkeys from disk and try them one by one, we had
to work around this.

Cheers,
Stef


// E.g. of pubKey:
//  30  81 9f
//    30  0d
//      06  09  2a 86 48 86 f7 0d 01 01 01
//      05  00
//    03  81 8d
//      00
//        30  81 89
//          02  81 81  00 83 b3 ba ... 16 41
//          02  03  01 00 01
void *CSOD::pubKey2DummyCert(CMS_ContentInfo *cms, unsigned char *pucPubKey, 
unsigned long iPubKeyLen)
{
        // Check that we have exactly 1 signerInfo field
        CMS_SignerInfo *si = GetSignerInfo(cms);
        if (si == NULL || si->sid == NULL)
                return NULL;
        CMS_SignerIdentifier *sid = si->sid;

        // Convert pucPubKey ->  EVP_PKEY
     BIO *bio = BIO_new_mem_buf(pucPubKey, iPubKeyLen);
     if (bio == NULL)
         return NULL;
     EVP_PKEY *pubkey = d2i_PUBKEY_bio(bio, NULL);
        BIO_free(bio);
     if (pubkey == NULL)
         return NULL;

        // Create the unsigned cert
        X509 *x = X509_new();
        if (x == NULL) {
                EVP_PKEY_free(pubkey);
                return NULL;
        }

        // Add dummy data
        X509_set_version(x,2);
        X509_gmtime_adj(X509_get_notBefore(x), 0);
        X509_gmtime_adj(X509_get_notAfter(x), (long) 60*60*24*10);
        X509_set_pubkey(x,pubkey);
        struct X509_name_st *subj = X509_get_subject_name(x);
        X509_NAME_add_entry_by_txt(subj, "C", MBSTRING_ASC, (const unsigned 
char *) "BE", -1, -1, 0);
        X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC, (const unsigned 
char *) "Dummy", -1, -1, 0);

        // The signer info (issuer+serialnr or keyid) in the SOD file must be 
present
        // in the dummy cert we're making, because the CMS_verify() function 
needs this
        if (sid->type == CMS_SIGNERINFO_ISSUER_SERIAL)
        {
                X509_set_issuer_name(x, sid->d.issuerAndSerialNumber->issuer);
                X509_set_serialNumber(x, 
sid->d.issuerAndSerialNumber->serialNumber);
        }
        else if (sid->type == CMS_SIGNERINFO_KEYIDENTIFIER)
        {
                if (x->skid != NULL)
                        M_ASN1_OCTET_STRING_free(x->skid);
                x->skid = M_ASN1_OCTET_STRING_dup(sid->d.subjectKeyIdentifier);

                // Set a dummy issuer DN and serial nr
                ASN1_INTEGER_set(X509_get_serialNumber(x), 13);
                struct X509_name_st *issuer = X509_get_subject_name(x);
                X509_NAME_add_entry_by_txt(issuer, "C", MBSTRING_ASC, (const 
unsigned char *) "BE", -1, -1, 0);
                X509_NAME_add_entry_by_txt(issuer, "CN", MBSTRING_ASC, (const 
unsigned char *) "Dummy CA", -1, -1, 0);
        }

        // Sign the cert with just any private key,
        // CMS_verify() doesn't check this if flags = CMS_NO_SIGNER_CERT_VERIFY
        RSA *rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
        EVP_PKEY *privkey = EVP_PKEY_new();
        if (EVP_PKEY_assign_RSA(privkey, rsa)) {
                if (!X509_sign(x, privkey, EVP_sha1()))
                {
                        X509_free(x);
                        x = NULL;
                }
        }

        if (privkey != NULL)
                EVP_PKEY_free(privkey);

        return x;
}

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to