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 [email protected]
Automated List Manager [email protected]