From dc3d77c9e3028bf6797e3fb4baf22eac34374de8 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Tue, 28 Sep 2010 15:17:35 -0400 Subject: [PATCH 014/150] - take a stab at verifying signed data --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 108 +++++++++++++++++++++++- 1 files changed, 104 insertions(+), 4 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 3de824e..eae3724 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -58,7 +58,7 @@ struct _pkinit_plg_crypto_context { struct _pkinit_req_crypto_context { PLArenaPool *pool; SECKEYPrivateKey *client_seckey; /* used by clients */ - CERTCertificate *client_cert; /* used by KDCs */ + CERTCertificate *peer_cert; /* used by both clients and KDCs */ }; struct _pkinit_identity_crypto_context { @@ -1439,7 +1439,7 @@ cms_envelopeddata_create(krb5_context context, PLArenaPool *pool; SECItem plain, encoded; - if (req_cryptoctx->client_cert == NULL) { + if (req_cryptoctx->peer_cert == NULL) { return ENOENT; } @@ -1475,7 +1475,7 @@ cms_envelopeddata_create(krb5_context context, /* Create a recipient and add it to the enveloped-data pointer. */ recipient = NSS_CMSRecipientInfo_Create(msg, - req_cryptoctx->client_cert); + req_cryptoctx->peer_cert); if (recipient == NULL) { PORT_FreeArena(pool, PR_TRUE); return ENOMEM; @@ -1643,5 +1643,105 @@ cms_signeddata_verify(krb5_context context, unsigned int *authz_data_len, int *is_signed) { - return ENOSYS; + NSSCMSMessage *msg; + NSSCMSContentInfo *info; + NSSCMSSignedData *sdata; + NSSCMSSignerInfo *signer; + CERTCertDBHandle *certdb; + CERTCertificate *cert; + SECCertUsage usage; + SECStatus status; + PLArenaPool *pool; + SECItem *plain, encoded; + + pool = PORT_NewArena(sizeof(double)); + if (pool == NULL) { + return ENOMEM; + } + certdb = CERT_GetDefaultCertDB(); + + /* Decode the message. */ + encoded.data = signed_data; + encoded.len = signed_data_len; + msg = NSS_CMSMessage_CreateFromDER(&encoded, + NULL, NULL, + NULL, NULL, + NULL, NULL); + if (msg == NULL) { + return ENOMEM; + } + + /* Check whether or not it's signed. */ + info = NSS_CMSMessage_GetContentInfo(msg); + if (info == NULL) { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + + switch (NSS_CMSContentInfo_GetContentTypeTag(info)) { + case SEC_OID_PKCS7_SIGNED_DATA: + /* Check that we have exactly one signature, and fish out the + * signer information. */ + sdata = NSS_CMSContentInfo_GetContent(info); + if (NSS_CMSMessage_IsSigned(msg) && + (sdata != NULL) && + (NSS_CMSSignedData_SignerInfoCount(sdata) != 1)) { + *is_signed = 1; + } else { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + signer = NSS_CMSSignedData_GetSignerInfo(sdata, 0); + if (signer == NULL) { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + /* Verify the signer's certificate. */ + usage = certUsageSSLServer; + status = NSS_CMSSignedData_VerifySignerInfo(sdata, 0, certdb, + usage); + if (status != SECSuccess) { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + /* Pull out the payload. */ + info = NSS_CMSSignedData_GetContentInfo(sdata); + if (info == NULL) { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + plain = NSS_CMSContentInfo_GetContent(info); + /* Save the peer cert. */ + if (req_cryptoctx->peer_cert != NULL) { + CERT_DestroyCertificate(req_cryptoctx->peer_cert); + } + cert = NSS_CMSSignerInfo_GetSigningCertificate(signer, certdb); + req_cryptoctx->peer_cert = CERT_DupCertificate(cert); + break; + case SEC_OID_PKCS7_DATA: + *is_signed = 0; + plain = NSS_CMSContentInfo_GetContent(info); + break; + default: + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + + /* Export the payload. */ + if ((plain == NULL) || + (secitem_to_buf_len(plain, payload, payload_len) != 0)) { + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + return ENOMEM; + } + NSS_CMSMessage_Destroy(msg); + PORT_FreeArena(pool, PR_TRUE); + + return 0; } -- 1.7.6.4