From 324e8176816fe7c877b7e33331ed8fca4841456a Mon Sep 17 00:00:00 2001
From: Nalin Dahyabhai <nalin@dahyabhai.net>
Date: Tue, 28 Sep 2010 11:34:34 -0400
Subject: [PATCH 013/150] - first cut at signing/enveloping/wrapping for
 senders

---
 src/plugins/preauth/pkinit/pkinit_crypto_nss.c |  219 +++++++++++++++++++++++-
 1 files changed, 213 insertions(+), 6 deletions(-)

diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
index df0b81a..3de824e 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c
@@ -43,6 +43,7 @@
 #include <pk11pub.h>
 #include <pk11pqg.h>
 #include <cert.h>
+#include <cms.h>
 #include <keyhi.h>
 #include <secoidt.h>
 
@@ -56,7 +57,8 @@ struct _pkinit_plg_crypto_context {
 
 struct _pkinit_req_crypto_context {
 	PLArenaPool *pool;
-	SECKEYPrivateKey *client_seckey;
+	SECKEYPrivateKey *client_seckey; /* used by clients */
+	CERTCertificate *client_cert; /* used by KDCs */
 };
 
 struct _pkinit_identity_crypto_context {
@@ -1112,10 +1114,10 @@ static SECItem pkinit_kp_kdc = {
 	.data = oid_pkinit_key_purpose_kdc_bytes,
 	.len = 7,
 };
-static unsigned char oid_ms_sc_login_key_purpose[] =
+static unsigned char oid_ms_sc_login_key_purpose_bytes[] =
 	{0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x02};
 static SECItem pkinit_kp_mssclogin = {
-	.data = oid_ms_sc_login_key_purpose,
+	.data = oid_ms_sc_login_key_purpose_bytes,
 	.len = 10,
 };
 static unsigned int
@@ -1372,7 +1374,49 @@ cms_contentinfo_create(krb5_context context,
 		       unsigned char *in_data, unsigned int in_length,
 		       unsigned char **out_data, unsigned int *out_data_len)
 {
-	return ENOSYS;
+	NSSCMSMessage *msg;
+	NSSCMSContentInfo *info;
+	PLArenaPool *pool;
+	SECItem plain, encoded;
+
+	pool = PORT_NewArena(sizeof(double));
+	if (pool == NULL) {
+		return ENOMEM;
+	}
+
+	msg = NSS_CMSMessage_Create(pool);
+	if (msg == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	info = NSS_CMSMessage_GetContentInfo(msg);
+	if (info == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	plain.data = in_data;
+	plain.len = in_length;
+	if (NSS_CMSContentInfo_SetContent_Data(msg, info, &plain,
+					       PR_FALSE) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	if (NSS_CMSDEREncode(msg, NULL, &encoded, pool) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	if (secitem_to_buf_len(&encoded, out_data, out_data_len) != 0) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	PORT_FreeArena(pool, PR_TRUE);
+
+	return 0;
 }
 
 krb5_error_code
@@ -1388,7 +1432,86 @@ cms_envelopeddata_create(krb5_context context,
 			 unsigned int *envel_data_len)
 
 {
-	return ENOSYS;
+	NSSCMSMessage *msg;
+	NSSCMSContentInfo *info;
+	NSSCMSEnvelopedData *env;
+	NSSCMSRecipientInfo *recipient;
+	PLArenaPool *pool;
+	SECItem plain, encoded;
+
+	if (req_cryptoctx->client_cert == NULL) {
+		return ENOENT;
+	}
+
+	pool = PORT_NewArena(sizeof(double));
+	if (pool == NULL) {
+		return ENOMEM;
+	}
+
+	/* Create the containing message. */
+	msg = NSS_CMSMessage_Create(pool);
+	if (msg == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Create an enveloped-data pointer and set it as the message's
+	 * contents. */
+	env = NSS_CMSEnvelopedData_Create(msg, SEC_OID_CMS_3DES_KEY_WRAP, 0);
+	if (env == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	info = NSS_CMSMessage_GetContentInfo(msg);
+	if (info == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSContentInfo_SetContent_EnvelopedData(msg, info,
+							env) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Create a recipient and add it to the enveloped-data pointer. */
+	recipient = NSS_CMSRecipientInfo_Create(msg,
+						req_cryptoctx->client_cert);
+	if (recipient == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSEnvelopedData_AddRecipient(env, recipient) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Set the raw data as the contents for the enveloped-data pointer. */
+	plain.data = key_pack;
+	plain.len = key_pack_len;
+	info = NSS_CMSEnvelopedData_GetContentInfo(env);
+	if (info == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSContentInfo_SetContent_Data(msg, info, &plain,
+					       PR_FALSE) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Encode and export. */
+	if (NSS_CMSDEREncode(msg, NULL, &encoded, pool) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (secitem_to_buf_len(&encoded, envel_data, envel_data_len) != 0) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	PORT_FreeArena(pool, PR_TRUE);
+
+	return 0;
 }
 
 krb5_error_code
@@ -1418,7 +1541,91 @@ cms_signeddata_create(krb5_context context,
 		      unsigned char **signed_data,
 		      unsigned int *signed_data_len)
 {
-	return ENOSYS;
+	NSSCMSMessage *msg;
+	NSSCMSContentInfo *info;
+	NSSCMSSignedData *sdata;
+	NSSCMSSignerInfo *signer;
+	PLArenaPool *pool;
+	SECItem plain, encoded;
+
+	if (id_cryptoctx->cert == NULL) {
+		return ENOENT;
+	}
+
+	pool = PORT_NewArena(sizeof(double));
+	if (pool == NULL) {
+		return ENOMEM;
+	}
+
+	/* Create the containing message. */
+	msg = NSS_CMSMessage_Create(pool);
+	if (msg == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Create a signed-data pointer and set it as the message's
+	 * contents. */
+	sdata = NSS_CMSSignedData_Create(msg);
+	if (sdata == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	info = NSS_CMSMessage_GetContentInfo(msg);
+	if (info == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSContentInfo_SetContent_SignedData(msg, info,
+						     sdata) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Create a signer and add it to the signed-data pointer. */
+	signer = NSS_CMSSignerInfo_Create(msg, id_cryptoctx->cert,
+					  SEC_OID_SHA1);
+	if (signer == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSSignerInfo_IncludeCerts(signer, NSSCMSCM_CertChainWithRoot,
+					   certUsageAnyCA) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSSignedData_AddSignerInfo(sdata, signer) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Set the raw data as the contents for the signed-data pointer. */
+	plain.data = payload;
+	plain.len = payload_len;
+	info = NSS_CMSSignedData_GetContentInfo(sdata);
+	if (info == NULL) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (NSS_CMSContentInfo_SetContent_Data(msg, info, &plain,
+					       PR_FALSE) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	/* Encode and export. */
+	if (NSS_CMSDEREncode(msg, NULL, &encoded, pool) != SECSuccess) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+	if (secitem_to_buf_len(&encoded, signed_data, signed_data_len) != 0) {
+		PORT_FreeArena(pool, PR_TRUE);
+		return ENOMEM;
+	}
+
+	PORT_FreeArena(pool, PR_TRUE);
+
+	return 0;
 }
 
 krb5_error_code
-- 
1.7.6.4

