Add hx509_cms_create_signed() that allows signing with 0 or more certs.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24580 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		
							
								
								
									
										334
									
								
								lib/hx509/cms.c
									
									
									
									
									
								
							
							
						
						
									
										334
									
								
								lib/hx509/cms.c
									
									
									
									
									
								
							| @@ -1131,26 +1131,52 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 			  hx509_certs pool, | ||||
| 			  heim_octet_string *signed_data) | ||||
| { | ||||
|     AlgorithmIdentifier digest; | ||||
|     hx509_name name; | ||||
|     SignerInfo *signer_info; | ||||
|     heim_octet_string buf, content, sigdata = { 0, NULL }; | ||||
|     hx509_certs certs; | ||||
|     int ret = 0; | ||||
|  | ||||
|     signed_data->data = NULL; | ||||
|     signed_data->length = 0; | ||||
|  | ||||
|     ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs); | ||||
|     if (ret) | ||||
| 	return ret; | ||||
|     ret = hx509_certs_add(context, certs, cert); | ||||
|  | ||||
|     ret = hx509_cms_create_signed(context, flags, eContentType, data, length, | ||||
| 				  digest_alg, certs, peer, anchors, pool, | ||||
| 				  signed_data); | ||||
|  | ||||
|     hx509_certs_free(&certs); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| struct sigctx { | ||||
|     SignedData sd; | ||||
|     int ret; | ||||
|     const AlgorithmIdentifier *digest_alg; | ||||
|     const heim_oid *eContentType; | ||||
|     heim_octet_string content; | ||||
|     hx509_peer_info peer; | ||||
|     int cmsidflag; | ||||
|     hx509_certs certs; | ||||
|     hx509_certs anchors; | ||||
|     hx509_certs pool; | ||||
| }; | ||||
|  | ||||
| static int | ||||
| sig_process(hx509_context context, void *ctx, hx509_cert cert) | ||||
| { | ||||
|     struct sigctx *sigctx = ctx; | ||||
|     heim_octet_string buf, sigdata = { 0, NULL }; | ||||
|     SignerInfo *signer_info = NULL; | ||||
|     AlgorithmIdentifier digest; | ||||
|     size_t size; | ||||
|     void *ptr; | ||||
|     int ret; | ||||
|     SignedData *sd = &sigctx->sd; | ||||
|     hx509_path path; | ||||
|     int cmsidflag = CMS_ID_SKI; | ||||
|  | ||||
|     memset(&sd, 0, sizeof(sd)); | ||||
|     memset(&name, 0, sizeof(name)); | ||||
|     memset(&path, 0, sizeof(path)); | ||||
|     memset(&digest, 0, sizeof(digest)); | ||||
|  | ||||
|     content.data = rk_UNCONST(data); | ||||
|     content.length = length; | ||||
|  | ||||
|     if (flags & HX509_CMS_SIGATURE_ID_NAME) | ||||
| 	cmsidflag = CMS_ID_NAME; | ||||
|     memset(&path, 0, sizeof(path)); | ||||
|  | ||||
|     if (_hx509_cert_private_key(cert) == NULL) { | ||||
| 	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, | ||||
| @@ -1158,55 +1184,37 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	return HX509_PRIVATE_KEY_MISSING; | ||||
|     } | ||||
|  | ||||
|     if (digest_alg == NULL) { | ||||
| 	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, | ||||
| 				  _hx509_cert_private_key(cert), peer, &digest); | ||||
|     } else { | ||||
| 	ret = copy_AlgorithmIdentifier(digest_alg, &digest); | ||||
|     if (sigctx->digest_alg) { | ||||
| 	ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest); | ||||
| 	if (ret) | ||||
| 	    hx509_clear_error_string(context); | ||||
|     } else { | ||||
| 	ret = hx509_crypto_select(context, HX509_SELECT_DIGEST, | ||||
| 				  _hx509_cert_private_key(cert),  | ||||
| 				  sigctx->peer, &digest); | ||||
|     } | ||||
|     if (ret) | ||||
| 	goto out; | ||||
|  | ||||
|     sd.version = CMSVersion_v3; | ||||
|     /* | ||||
|      * Allocate on more signerInfo and do the signature processing | ||||
|      */ | ||||
|  | ||||
|     if (eContentType == NULL) | ||||
| 	eContentType = oid_id_pkcs7_data(); | ||||
|  | ||||
|     der_copy_oid(eContentType, &sd.encapContentInfo.eContentType); | ||||
|  | ||||
|     /* */ | ||||
|     if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { | ||||
| 	ALLOC(sd.encapContentInfo.eContent, 1); | ||||
| 	if (sd.encapContentInfo.eContent == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	 | ||||
| 	sd.encapContentInfo.eContent->data = malloc(length); | ||||
| 	if (sd.encapContentInfo.eContent->data == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	memcpy(sd.encapContentInfo.eContent->data, data, length); | ||||
| 	sd.encapContentInfo.eContent->length = length; | ||||
|     } | ||||
|  | ||||
|     ALLOC_SEQ(&sd.signerInfos, 1); | ||||
|     if (sd.signerInfos.val == NULL) { | ||||
| 	hx509_clear_error_string(context); | ||||
|     ptr = realloc(sd->signerInfos.val, | ||||
| 		  (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0])); | ||||
|     if (ptr == NULL) { | ||||
| 	ret = ENOMEM; | ||||
| 	goto out; | ||||
|     } | ||||
|     sd->signerInfos.val = ptr; | ||||
|  | ||||
|     signer_info = &sd.signerInfos.val[0]; | ||||
|     signer_info = &sd->signerInfos.val[sd->signerInfos.len]; | ||||
|  | ||||
|     memset(signer_info, 0, sizeof(*signer_info)); | ||||
|  | ||||
|     signer_info->version = 1; | ||||
|  | ||||
|     ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); | ||||
|     ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid); | ||||
|     if (ret) { | ||||
| 	hx509_clear_error_string(context); | ||||
| 	goto out; | ||||
| @@ -1215,7 +1223,6 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
|     signer_info->signedAttrs = NULL; | ||||
|     signer_info->unsignedAttrs = NULL; | ||||
|  | ||||
|  | ||||
|     ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm); | ||||
|     if (ret) { | ||||
| 	hx509_clear_error_string(context); | ||||
| @@ -1226,7 +1233,7 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
|      * If it isn't pkcs7-data send signedAttributes | ||||
|      */ | ||||
|  | ||||
|     if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) { | ||||
|     if (der_heim_oid_cmp(sigctx->eContentType, oid_id_pkcs7_data()) != 0) { | ||||
| 	CMSAttributes sa;	 | ||||
| 	heim_octet_string sig; | ||||
|  | ||||
| @@ -1239,7 +1246,7 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	ret = _hx509_create_signature(context, | ||||
| 				      NULL, | ||||
| 				      &digest, | ||||
| 				      &content, | ||||
| 				      &sigctx->content, | ||||
| 				      NULL, | ||||
| 				      &sig); | ||||
| 	if (ret) | ||||
| @@ -1264,6 +1271,7 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 				oid_id_pkcs9_messageDigest(), | ||||
| 				&buf); | ||||
| 	if (ret) { | ||||
| 	    free(buf.data); | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    goto out; | ||||
| 	} | ||||
| @@ -1272,7 +1280,7 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	ASN1_MALLOC_ENCODE(ContentType, | ||||
| 			   buf.data, | ||||
| 			   buf.length, | ||||
| 			   eContentType, | ||||
| 			   sigctx->eContentType, | ||||
| 			   &size, | ||||
| 			   ret); | ||||
| 	if (ret) | ||||
| @@ -1285,6 +1293,7 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 				oid_id_pkcs9_contentType(), | ||||
| 				&buf); | ||||
| 	if (ret) { | ||||
| 	    free(buf.data); | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    goto out; | ||||
| 	} | ||||
| @@ -1305,16 +1314,15 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	if (size != sigdata.length) | ||||
| 	    _hx509_abort("internal ASN.1 encoder error"); | ||||
|     } else { | ||||
| 	sigdata.data = content.data; | ||||
| 	sigdata.length = content.length; | ||||
| 	sigdata.data = sigctx->content.data; | ||||
| 	sigdata.length = sigctx->content.length; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     { | ||||
| 	AlgorithmIdentifier sigalg; | ||||
|  | ||||
| 	ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG, | ||||
| 				  _hx509_cert_private_key(cert), peer, | ||||
| 				  _hx509_cert_private_key(cert), sigctx->peer, | ||||
| 				  &sigalg); | ||||
| 	if (ret) | ||||
| 	    goto out; | ||||
| @@ -1330,54 +1338,30 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	    goto out; | ||||
|     } | ||||
|  | ||||
|     ALLOC_SEQ(&sd.digestAlgorithms, 1); | ||||
|     if (sd.digestAlgorithms.val == NULL) { | ||||
| 	ret = ENOMEM; | ||||
| 	hx509_clear_error_string(context); | ||||
| 	goto out; | ||||
|     } | ||||
|  | ||||
|     ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]); | ||||
|     if (ret) { | ||||
| 	hx509_clear_error_string(context); | ||||
| 	goto out; | ||||
|     } | ||||
|     sigctx->sd.signerInfos.len++; | ||||
|     signer_info = NULL; | ||||
|  | ||||
|     /* | ||||
|      * Provide best effort path | ||||
|      */ | ||||
|     if (pool) { | ||||
| 	_hx509_calculate_path(context, | ||||
| 			      HX509_CALCULATE_PATH_NO_ANCHOR,			 | ||||
| 			      time(NULL), | ||||
| 			      anchors, | ||||
| 			      0, | ||||
| 			      cert, | ||||
| 			      pool, | ||||
| 			      &path); | ||||
|     } else | ||||
| 	_hx509_path_append(context, &path, cert); | ||||
|     if (sigctx->certs) { | ||||
| 	unsigned int i; | ||||
|  | ||||
|  | ||||
|     if (path.len) { | ||||
| 	int i; | ||||
|  | ||||
| 	ALLOC(sd.certificates, 1); | ||||
| 	if (sd.certificates == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	ALLOC_SEQ(sd.certificates, path.len); | ||||
| 	if (sd.certificates->val == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	if (sigctx->pool) { | ||||
| 	    _hx509_calculate_path(context, | ||||
| 				  HX509_CALCULATE_PATH_NO_ANCHOR, | ||||
| 				  time(NULL), | ||||
| 				  sigctx->anchors, | ||||
| 				  0, | ||||
| 				  cert, | ||||
| 				  sigctx->pool, | ||||
| 				  &path); | ||||
| 	} else | ||||
| 	    _hx509_path_append(context, &path, cert); | ||||
|  | ||||
| 	for (i = 0; i < path.len; i++) { | ||||
| 	    ret = hx509_cert_binary(context, path.val[i], | ||||
| 				    &sd.certificates->val[i]); | ||||
| 	    /* XXX remove dups */ | ||||
| 	    ret = hx509_certs_add(context, sigctx->certs, path.val[i]); | ||||
| 	    if (ret) { | ||||
| 		hx509_clear_error_string(context); | ||||
| 		goto out; | ||||
| @@ -1385,9 +1369,152 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|  out: | ||||
|     if (signer_info) | ||||
| 	free_SignerInfo(signer_info); | ||||
|     if (sigdata.data != sigctx->content.data) | ||||
| 	der_free_octet_string(&sigdata); | ||||
|     _hx509_path_free(&path); | ||||
|     free_AlgorithmIdentifier(&digest); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int | ||||
| cert_process(hx509_context context, void *ctx, hx509_cert cert) | ||||
| { | ||||
|     struct sigctx *sigctx = ctx; | ||||
|     const unsigned int i = sigctx->sd.certificates->len; | ||||
|     void *ptr; | ||||
|     int ret; | ||||
|      | ||||
|     ptr = realloc(sigctx->sd.certificates->val, | ||||
| 		  (i + 1) * sizeof(sigctx->sd.certificates->val[0])); | ||||
|     if (ptr == NULL) | ||||
| 	return ENOMEM; | ||||
|     sigctx->sd.certificates->val = ptr; | ||||
|  | ||||
|     ret = hx509_cert_binary(context, cert, | ||||
| 			    &sigctx->sd.certificates->val[i]); | ||||
|     if (ret == 0) | ||||
| 	sigctx->sd.certificates->len++; | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| int | ||||
| hx509_cms_create_signed(hx509_context context, | ||||
| 			int flags, | ||||
| 			const heim_oid *eContentType, | ||||
| 			const void *data, size_t length, | ||||
| 			const AlgorithmIdentifier *digest_alg, | ||||
| 			hx509_certs certs, | ||||
| 			hx509_peer_info peer, | ||||
| 			hx509_certs anchors, | ||||
| 			hx509_certs pool, | ||||
| 			heim_octet_string *signed_data) | ||||
| { | ||||
|     unsigned int i; | ||||
|     hx509_name name; | ||||
|     int ret; | ||||
|     size_t size; | ||||
|     struct sigctx sigctx; | ||||
|  | ||||
|     memset(&sigctx, 0, sizeof(sigctx)); | ||||
|     memset(&name, 0, sizeof(name)); | ||||
|  | ||||
|     if (eContentType == NULL) | ||||
| 	eContentType = oid_id_pkcs7_data(); | ||||
|  | ||||
|     sigctx.digest_alg = digest_alg; | ||||
|     sigctx.content.data = rk_UNCONST(data); | ||||
|     sigctx.content.length = length; | ||||
|     sigctx.eContentType = eContentType; | ||||
|     sigctx.peer = peer; | ||||
|     if (flags & HX509_CMS_SIGATURE_ID_NAME) | ||||
| 	sigctx.cmsidflag = CMS_ID_NAME; | ||||
|     else | ||||
| 	sigctx.cmsidflag = CMS_ID_SKI; | ||||
|  | ||||
|     ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs); | ||||
|     if (ret) | ||||
| 	return ret; | ||||
|  | ||||
|     sigctx.anchors = anchors; | ||||
|     sigctx.pool = pool; | ||||
|  | ||||
|     sigctx.sd.version = CMSVersion_v3; | ||||
|  | ||||
|     der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); | ||||
|  | ||||
|     /** | ||||
|      * Use HX509_CMS_SIGATURE_DETACHED to create detached signatures. | ||||
|      */ | ||||
|     if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) { | ||||
| 	ALLOC(sigctx.sd.encapContentInfo.eContent, 1); | ||||
| 	if (sigctx.sd.encapContentInfo.eContent == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	 | ||||
| 	sigctx.sd.encapContentInfo.eContent->data = malloc(length); | ||||
| 	if (sigctx.sd.encapContentInfo.eContent->data == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length); | ||||
| 	sigctx.sd.encapContentInfo.eContent->length = length; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Use HX509_CMS_SIGATURE_NO_SIGNER to create no sigInfo (no | ||||
|      * sigatures). | ||||
|      */ | ||||
|     if ((flags & HX509_CMS_SIGATURE_NO_SIGNER) == 0) { | ||||
| 	ret = hx509_certs_iter(context, certs, sig_process, &sigctx); | ||||
| 	if (ret) | ||||
| 	    goto out; | ||||
|     } | ||||
|  | ||||
|     if (sigctx.sd.signerInfos.len) { | ||||
| 	ALLOC_SEQ(&sigctx.sd.digestAlgorithms, sigctx.sd.signerInfos.len); | ||||
| 	if (sigctx.sd.digestAlgorithms.val == NULL) { | ||||
| 	    ret = ENOMEM; | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    goto out; | ||||
| 	} | ||||
| 	 | ||||
| 	/* XXX remove dups */ | ||||
| 	for (i = 0; i < sigctx.sd.signerInfos.len; i++) { | ||||
| 	    AlgorithmIdentifier *di = | ||||
| 		&sigctx.sd.signerInfos.val[i].digestAlgorithm; | ||||
| 	    ret = copy_AlgorithmIdentifier(di, | ||||
| 					   &sigctx.sd.digestAlgorithms.val[i]); | ||||
| 	    if (ret) { | ||||
| 		hx509_clear_error_string(context); | ||||
| 		goto out; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (sigctx.certs) { | ||||
| 	ALLOC(sigctx.sd.certificates, 1); | ||||
| 	if (sigctx.sd.certificates == NULL) { | ||||
| 	    hx509_clear_error_string(context); | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
|  | ||||
| 	ret = hx509_certs_iter(context, sigctx.certs, cert_process, &sigctx); | ||||
| 	if (ret) | ||||
| 	    goto out; | ||||
|     } | ||||
|  | ||||
|     ASN1_MALLOC_ENCODE(SignedData, | ||||
| 		       signed_data->data, signed_data->length, | ||||
| 		       &sd, &size, ret); | ||||
| 		       &sigctx.sd, &size, ret); | ||||
|     if (ret) { | ||||
| 	hx509_clear_error_string(context); | ||||
| 	goto out; | ||||
| @@ -1396,11 +1523,8 @@ hx509_cms_create_signed_1(hx509_context context, | ||||
| 	_hx509_abort("internal ASN.1 encoder error"); | ||||
|  | ||||
| out: | ||||
|     if (sigdata.data != content.data) | ||||
| 	der_free_octet_string(&sigdata); | ||||
|     free_AlgorithmIdentifier(&digest); | ||||
|     _hx509_path_free(&path); | ||||
|     free_SignedData(&sd); | ||||
|     hx509_certs_free(&sigctx.certs); | ||||
|     free_SignedData(&sigctx.sd); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Love Hörnquist Åstrand
					Love Hörnquist Åstrand