hx509: support reading private keys from PEM files
This commit adds: - hx509_cert_init_private_key() for creating an hx509_cert object that has just a private key - hx509_cert_have_private_key_only() for checking whether an hx509_cert object has just a private key This also generalizes the get_key() internal function in hxtool, which is tasked with reding or generating a private key for use in signing CSRs. Now hxtool request-create can read/write private keys to/from PEM files, not just DER files. This is needed to support key types other than just RSA for CSRs and certificates.
This commit is contained in:
		| @@ -212,6 +212,29 @@ _hx509_cert_get_version(const Certificate *t) | ||||
|     return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; | ||||
| } | ||||
|  | ||||
| static hx509_cert | ||||
| cert_init(hx509_context context, heim_error_t *error) | ||||
| { | ||||
|     hx509_cert cert; | ||||
|  | ||||
|     cert = malloc(sizeof(*cert)); | ||||
|     if (cert == NULL) { | ||||
| 	if (error) | ||||
| 	    *error = heim_error_create_enomem(); | ||||
| 	return NULL; | ||||
|     } | ||||
|     cert->ref = 1; | ||||
|     cert->friendlyname = NULL; | ||||
|     cert->attrs.len = 0; | ||||
|     cert->attrs.val = NULL; | ||||
|     cert->private_key = NULL; | ||||
|     cert->basename = NULL; | ||||
|     cert->release = NULL; | ||||
|     cert->ctx = NULL; | ||||
|     cert->data= NULL; | ||||
|     return cert; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Allocate and init an hx509 certificate object from the decoded | ||||
|  * certificate `c´. | ||||
| @@ -231,20 +254,8 @@ hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error | ||||
|     hx509_cert cert; | ||||
|     int ret; | ||||
|  | ||||
|     cert = malloc(sizeof(*cert)); | ||||
|     if (cert == NULL) { | ||||
| 	if (error) | ||||
| 	    *error = heim_error_create_enomem(); | ||||
| 	return NULL; | ||||
|     } | ||||
|     cert->ref = 1; | ||||
|     cert->friendlyname = NULL; | ||||
|     cert->attrs.len = 0; | ||||
|     cert->attrs.val = NULL; | ||||
|     cert->private_key = NULL; | ||||
|     cert->basename = NULL; | ||||
|     cert->release = NULL; | ||||
|     cert->ctx = NULL; | ||||
|     if ((cert = cert_init(context, error)) == NULL) | ||||
|         return NULL; | ||||
|  | ||||
|     cert->data = calloc(1, sizeof(*(cert->data))); | ||||
|     if (cert->data == NULL) { | ||||
| @@ -262,6 +273,31 @@ hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error | ||||
|     return cert; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Allocate and init an hx509 certificate object containing only a private key | ||||
|  * (but no Certificate). | ||||
|  * | ||||
|  * @param context A hx509 context. | ||||
|  * @param key | ||||
|  * @param error | ||||
|  * | ||||
|  * @return Returns an hx509 certificate | ||||
|  * | ||||
|  * @ingroup hx509_cert | ||||
|  */ | ||||
|  | ||||
| HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL | ||||
| hx509_cert_init_private_key(hx509_context context, | ||||
|                             hx509_private_key key, | ||||
|                             heim_error_t *error) | ||||
| { | ||||
|     hx509_cert cert; | ||||
|  | ||||
|     if ((cert = cert_init(context, error))) | ||||
|         (void) _hx509_cert_assign_key(cert, key); | ||||
|     return cert; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Just like hx509_cert_init(), but instead of a decode certificate | ||||
|  * takes an pointer and length to a memory region that contains a | ||||
| @@ -360,7 +396,8 @@ hx509_cert_free(hx509_cert cert) | ||||
|     if (cert->private_key) | ||||
| 	hx509_private_key_free(&cert->private_key); | ||||
|  | ||||
|     free_Certificate(cert->data); | ||||
|     if (cert->data) | ||||
|         free_Certificate(cert->data); | ||||
|     free(cert->data); | ||||
|  | ||||
|     for (i = 0; i < cert->attrs.len; i++) { | ||||
| @@ -1598,12 +1635,36 @@ _hx509_cert_private_key(hx509_cert p) | ||||
|     return p->private_key; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Indicate whether a hx509_cert has a private key. | ||||
|  * | ||||
|  * @param p a hx509 certificate | ||||
|  * | ||||
|  * @return 1 if p has a private key, 0 otherwise. | ||||
|  * | ||||
|  * @ingroup hx509_cert | ||||
|  */ | ||||
| HX509_LIB_FUNCTION int HX509_LIB_CALL | ||||
| hx509_cert_have_private_key(hx509_cert p) | ||||
| { | ||||
|     return p->private_key ? 1 : 0; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Indicate whether a hx509_cert has a private key only (no certificate). | ||||
|  * | ||||
|  * @param p a hx509 certificate | ||||
|  * | ||||
|  * @return 1 if p has a private key only (no certificate), 0 otherwise. | ||||
|  * | ||||
|  * @ingroup hx509_cert | ||||
|  */ | ||||
| HX509_LIB_FUNCTION int HX509_LIB_CALL | ||||
| hx509_cert_have_private_key_only(hx509_cert p) | ||||
| { | ||||
|     return p->private_key && !p->data ? 1 : 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| HX509_LIB_FUNCTION int HX509_LIB_CALL | ||||
| _hx509_cert_private_key_exportable(hx509_cert p) | ||||
|   | ||||
| @@ -535,19 +535,28 @@ store_func(hx509_context context, void *ctx, hx509_cert c) | ||||
|     heim_octet_string data; | ||||
|     int ret; | ||||
|  | ||||
|     ret = hx509_cert_binary(context, c, &data); | ||||
|     if (ret) | ||||
| 	return ret; | ||||
|     if (hx509_cert_have_private_key_only(c)) { | ||||
|         data.length = 0; | ||||
|         data.data = NULL; | ||||
|     } else { | ||||
|         ret = hx509_cert_binary(context, c, &data); | ||||
|         if (ret) | ||||
|             return ret; | ||||
|     } | ||||
|  | ||||
|     switch (sc->format) { | ||||
|     case USE_DER: | ||||
| 	fwrite(data.data, data.length, 1, sc->f); | ||||
| 	free(data.data); | ||||
|         if (data.data) { | ||||
|             fwrite(data.data, data.length, 1, sc->f); | ||||
|             free(data.data); | ||||
|         } /* XXX else write private key instead */ | ||||
| 	break; | ||||
|     case USE_PEM: | ||||
| 	hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, | ||||
| 			data.data, data.length); | ||||
| 	free(data.data); | ||||
|         if (data.data) { | ||||
|             hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, | ||||
|                             data.data, data.length); | ||||
|             free(data.data); | ||||
|         } | ||||
| 	if (_hx509_cert_private_key_exportable(c)) { | ||||
| 	    hx509_private_key key = _hx509_cert_private_key(c); | ||||
| 	    ret = _hx509_private_key_export(context, key, | ||||
|   | ||||
| @@ -80,8 +80,11 @@ EXPORTS | ||||
| 	hx509_cert_get_notBefore | ||||
| 	hx509_cert_get_serialnumber | ||||
| 	hx509_cert_get_subject | ||||
| 	hx509_cert_have_private_key | ||||
| 	hx509_cert_have_private_key_only | ||||
| 	hx509_cert_init | ||||
| 	hx509_cert_init_data | ||||
| 	hx509_cert_init_private_key | ||||
| 	hx509_cert_keyusage_print | ||||
| 	hx509_cert_ref | ||||
| 	hx509_cert_set_friendly_name | ||||
|   | ||||
| @@ -74,8 +74,11 @@ HEIMDAL_X509_1.2 { | ||||
| 		hx509_cert_get_subject; | ||||
| 		hx509_cert_get_issuer_unique_id; | ||||
| 		hx509_cert_get_subject_unique_id; | ||||
| 		hx509_cert_have_private_key; | ||||
| 		hx509_cert_have_private_key_only; | ||||
| 		hx509_cert_init; | ||||
| 		hx509_cert_init_data; | ||||
| 		hx509_cert_init_private_key; | ||||
| 		hx509_cert_keyusage_print; | ||||
| 		hx509_cert_public_encrypt; | ||||
| 		hx509_cert_ref; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams