mirror of https://github.com/openssl/openssl.git
				
				
				
			Add PKCS#12 documentation and new option in x509 to add certificate extensions.
This commit is contained in:
		
							parent
							
								
									73d2257d97
								
							
						
					
					
						commit
						b64f825671
					
				
							
								
								
									
										4
									
								
								CHANGES
								
								
								
								
							
							
						
						
									
										4
									
								
								CHANGES
								
								
								
								
							|  | @ -5,6 +5,10 @@ | ||||||
| 
 | 
 | ||||||
|  Changes between 0.9.2b and 0.9.3 |  Changes between 0.9.2b and 0.9.3 | ||||||
| 
 | 
 | ||||||
|  |   *) Add the PKCS#12 API documentation to openssl.txt. Preliminary support for | ||||||
|  |      extension adding in x509 utility. | ||||||
|  |      [Steve Henson] | ||||||
|  | 
 | ||||||
|   *) Remove NOPROTO sections and error code comments. |   *) Remove NOPROTO sections and error code comments. | ||||||
|      [Ulf Möller] |      [Ulf Möller] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								STATUS
								
								
								
								
							
							
						
						
									
										3
									
								
								STATUS
								
								
								
								
							|  | @ -1,6 +1,6 @@ | ||||||
| 
 | 
 | ||||||
|   OpenSSL STATUS                           Last modified at |   OpenSSL STATUS                           Last modified at | ||||||
|   ______________                           $Date: 1999/04/26 20:56:18 $ |   ______________                           $Date: 1999/04/27 00:36:14 $ | ||||||
| 
 | 
 | ||||||
|   DEVELOPMENT STATE |   DEVELOPMENT STATE | ||||||
| 
 | 
 | ||||||
|  | @ -43,7 +43,6 @@ | ||||||
|         PKCS#12 code cleanup and enhancement. |         PKCS#12 code cleanup and enhancement. | ||||||
| 	PKCS #8 and PKCS#5 v2.0 support. | 	PKCS #8 and PKCS#5 v2.0 support. | ||||||
| 	Private key, certificate and CRL API and implementation. | 	Private key, certificate and CRL API and implementation. | ||||||
| 	Redo error code and DEF file generation scripts. |  | ||||||
| 
 | 
 | ||||||
|     o Mark is currently working on: |     o Mark is currently working on: | ||||||
|         Folding in any changes that are in the C2Net code base that were |         Folding in any changes that are in the C2Net code base that were | ||||||
|  |  | ||||||
							
								
								
									
										87
									
								
								apps/x509.c
								
								
								
								
							
							
						
						
									
										87
									
								
								apps/x509.c
								
								
								
								
							|  | @ -114,16 +114,18 @@ static char *x509_usage[]={ | ||||||
| " -text           - print the certificate in text form\n", | " -text           - print the certificate in text form\n", | ||||||
| " -C              - print out C code forms\n", | " -C              - print out C code forms\n", | ||||||
| " -md2/-md5/-sha1/-mdc2 - digest to do an RSA sign with\n", | " -md2/-md5/-sha1/-mdc2 - digest to do an RSA sign with\n", | ||||||
|  | " -config         - configuration file with X509V3 extensions to add\n", | ||||||
| NULL | NULL | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx); | static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx); | ||||||
| static EVP_PKEY *load_key(char *file, int format); | static EVP_PKEY *load_key(char *file, int format); | ||||||
| static X509 *load_cert(char *file, int format); | static X509 *load_cert(char *file, int format); | ||||||
| static int sign (X509 *x, EVP_PKEY *pkey,int days,const EVP_MD *digest); | static int sign (X509 *x, EVP_PKEY *pkey,int days,const EVP_MD *digest, | ||||||
|  | 						LHASH *conf, char *section); | ||||||
| static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest, | static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest, | ||||||
| 			 X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial, | 			 X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial, | ||||||
| 			 int create,int days); | 			 int create,int days, LHASH *conf, char *section); | ||||||
| static int reqfile=0; | static int reqfile=0; | ||||||
| 
 | 
 | ||||||
| int MAIN(int argc, char **argv) | int MAIN(int argc, char **argv) | ||||||
|  | @ -148,6 +150,8 @@ int MAIN(int argc, char **argv) | ||||||
| 	int fingerprint=0; | 	int fingerprint=0; | ||||||
| 	char buf[256]; | 	char buf[256]; | ||||||
| 	const EVP_MD *md_alg,*digest=EVP_md5(); | 	const EVP_MD *md_alg,*digest=EVP_md5(); | ||||||
|  | 	LHASH *extconf = NULL; | ||||||
|  | 	char *extsect = NULL, *extfile = NULL; | ||||||
| 
 | 
 | ||||||
| 	reqfile=0; | 	reqfile=0; | ||||||
| 
 | 
 | ||||||
|  | @ -209,6 +213,11 @@ int MAIN(int argc, char **argv) | ||||||
| 				goto bad; | 				goto bad; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		else if (strcmp(*argv,"-config") == 0) | ||||||
|  | 			{ | ||||||
|  | 			if (--argc < 1) goto bad; | ||||||
|  | 			extfile= *(++argv); | ||||||
|  | 			} | ||||||
| 		else if (strcmp(*argv,"-in") == 0) | 		else if (strcmp(*argv,"-in") == 0) | ||||||
| 			{ | 			{ | ||||||
| 			if (--argc < 1) goto bad; | 			if (--argc < 1) goto bad; | ||||||
|  | @ -312,6 +321,34 @@ bad: | ||||||
| 		goto end; | 		goto end; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 	if (extfile) { | ||||||
|  | 		long errorline; | ||||||
|  | 		X509V3_CTX ctx; | ||||||
|  | 		if (!(extconf=CONF_load(NULL,extfile,&errorline))) { | ||||||
|  | 			if (errorline <= 0) | ||||||
|  | 				BIO_printf(bio_err, | ||||||
|  | 					"error loading the config file '%s'\n", | ||||||
|  | 								extfile); | ||||||
|  |                 	else | ||||||
|  |                         	BIO_printf(bio_err, | ||||||
|  | 				       "error on line %ld of config file '%s'\n" | ||||||
|  | 							,errorline,extfile); | ||||||
|  | 			goto end; | ||||||
|  | 		} | ||||||
|  | 		if(!(extsect = CONF_get_string(extconf, "default", | ||||||
|  | 					 "extensions"))) extsect = "default"; | ||||||
|  | 		X509V3_set_ctx_test(&ctx); | ||||||
|  | 		X509V3_set_conf_lhash(&ctx, extconf); | ||||||
|  | 		if(!X509V3_EXT_add_conf(extconf, &ctx, extsect, NULL)) { | ||||||
|  | 			BIO_printf(bio_err, | ||||||
|  | 				"Error Loading extension section %s\n", | ||||||
|  | 								 extsect); | ||||||
|  | 			ERR_print_errors(bio_err); | ||||||
|  | 			goto end; | ||||||
|  |                 } | ||||||
|  | 	}  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	if (reqfile) | 	if (reqfile) | ||||||
| 		{ | 		{ | ||||||
| 		EVP_PKEY *pkey; | 		EVP_PKEY *pkey; | ||||||
|  | @ -589,7 +626,8 @@ bad: | ||||||
| 		                        digest=EVP_dss1(); | 		                        digest=EVP_dss1(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 				if (!sign(x,Upkey,days,digest)) goto end; | 				if (!sign(x,Upkey,days,digest, | ||||||
|  | 						 extconf, extsect)) goto end; | ||||||
| 				} | 				} | ||||||
| 			else if (CA_flag == i) | 			else if (CA_flag == i) | ||||||
| 				{ | 				{ | ||||||
|  | @ -605,8 +643,8 @@ bad: | ||||||
| #endif | #endif | ||||||
| 				 | 				 | ||||||
| 				if (!x509_certify(ctx,CAfile,digest,x,xca, | 				if (!x509_certify(ctx,CAfile,digest,x,xca, | ||||||
| 					CApkey, | 					CApkey, CAserial,CA_createserial,days, | ||||||
| 					CAserial,CA_createserial,days)) | 					extconf, extsect)) | ||||||
| 					goto end; | 					goto end; | ||||||
| 				} | 				} | ||||||
| 			else if (x509req == i) | 			else if (x509req == i) | ||||||
|  | @ -680,22 +718,23 @@ bad: | ||||||
| 	ret=0; | 	ret=0; | ||||||
| end: | end: | ||||||
| 	OBJ_cleanup(); | 	OBJ_cleanup(); | ||||||
| 	if (out != NULL) BIO_free(out); | 	CONF_free(extconf); | ||||||
| 	if (STDout != NULL) BIO_free(STDout); | 	BIO_free(out); | ||||||
| 	if (ctx != NULL) X509_STORE_free(ctx); | 	BIO_free(STDout); | ||||||
| 	if (req != NULL) X509_REQ_free(req); | 	X509_STORE_free(ctx); | ||||||
| 	if (x != NULL) X509_free(x); | 	X509_REQ_free(req); | ||||||
| 	if (xca != NULL) X509_free(xca); | 	X509_free(x); | ||||||
| 	if (Upkey != NULL) EVP_PKEY_free(Upkey); | 	X509_free(xca); | ||||||
| 	if (CApkey != NULL) EVP_PKEY_free(CApkey); | 	EVP_PKEY_free(Upkey); | ||||||
| 	if (rq != NULL) X509_REQ_free(rq); | 	EVP_PKEY_free(CApkey); | ||||||
|  | 	X509_REQ_free(rq); | ||||||
| 	X509V3_EXT_cleanup(); | 	X509V3_EXT_cleanup(); | ||||||
| 	EXIT(ret); | 	EXIT(ret); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, | static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, | ||||||
| 	     X509 *x, X509 *xca, EVP_PKEY *pkey, char *serialfile, int create, | 	     X509 *x, X509 *xca, EVP_PKEY *pkey, char *serialfile, int create, | ||||||
| 	     int days) | 	     int days, LHASH *conf, char *section) | ||||||
| 	{ | 	{ | ||||||
| 	int ret=0; | 	int ret=0; | ||||||
| 	BIO *io=NULL; | 	BIO *io=NULL; | ||||||
|  | @ -828,6 +867,14 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, | ||||||
| 		} | 		} | ||||||
| 	EVP_PKEY_free(upkey); | 	EVP_PKEY_free(upkey); | ||||||
| 
 | 
 | ||||||
|  | 	if(conf) { | ||||||
|  | 		X509V3_CTX ctx; | ||||||
|  | 		X509_set_version(x,2); /* version 3 certificate */ | ||||||
|  |                 X509V3_set_ctx(&ctx, xca, x, NULL, NULL, 0); | ||||||
|  |                 X509V3_set_conf_lhash(&ctx, conf); | ||||||
|  |                 if(!X509V3_EXT_add_conf(conf, &ctx, section, x)) goto end; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (!X509_sign(x,pkey,digest)) goto end; | 	if (!X509_sign(x,pkey,digest)) goto end; | ||||||
| 	ret=1; | 	ret=1; | ||||||
| end: | end: | ||||||
|  | @ -1014,7 +1061,8 @@ end: | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| /* self sign */ | /* self sign */ | ||||||
| static int sign(X509 *x, EVP_PKEY *pkey, int days, const EVP_MD *digest) | static int sign(X509 *x, EVP_PKEY *pkey, int days, const EVP_MD *digest,  | ||||||
|  | 						LHASH *conf, char *section) | ||||||
| 	{ | 	{ | ||||||
| 
 | 
 | ||||||
| 	EVP_PKEY *pktmp; | 	EVP_PKEY *pktmp; | ||||||
|  | @ -1035,6 +1083,13 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, const EVP_MD *digest) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	if (!X509_set_pubkey(x,pkey)) goto err; | 	if (!X509_set_pubkey(x,pkey)) goto err; | ||||||
|  | 	if(conf) { | ||||||
|  | 		X509V3_CTX ctx; | ||||||
|  | 		X509_set_version(x,2); /* version 3 certificate */ | ||||||
|  |                 X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0); | ||||||
|  |                 X509V3_set_conf_lhash(&ctx, conf); | ||||||
|  |                 if(!X509V3_EXT_add_conf(conf, &ctx, section, x)) goto err; | ||||||
|  | 	} | ||||||
| 	if (!X509_sign(x,pkey,digest)) goto err; | 	if (!X509_sign(x,pkey,digest)) goto err; | ||||||
| 	return(1); | 	return(1); | ||||||
| err: | err: | ||||||
|  |  | ||||||
|  | @ -83,8 +83,7 @@ int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen, | ||||||
| 	unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; | 	unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; | ||||||
| 	int i; | 	int i; | ||||||
| 	pbelu.pbe_nid = OBJ_obj2nid(pbe_obj); | 	pbelu.pbe_nid = OBJ_obj2nid(pbe_obj); | ||||||
| 	if ((pbelu.pbe_nid != NID_undef) && pbe_algs)  | 	if (pbelu.pbe_nid != NID_undef) i = sk_find(pbe_algs, (char *)&pbelu); | ||||||
| 			i = sk_find (pbe_algs, (char *)&pbelu); |  | ||||||
| 	else i = -1; | 	else i = -1; | ||||||
| 
 | 
 | ||||||
| 	if (i == -1) { | 	if (i == -1) { | ||||||
|  | @ -167,4 +166,5 @@ int EVP_PBE_alg_add (int nid, EVP_CIPHER *cipher, EVP_MD *md, | ||||||
| void EVP_PBE_cleanup(void) | void EVP_PBE_cleanup(void) | ||||||
| { | { | ||||||
| 	sk_pop_free(pbe_algs, FreeFunc); | 	sk_pop_free(pbe_algs, FreeFunc); | ||||||
|  | 	pbe_algs = NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -135,6 +135,7 @@ int sk_insert(STACK *st, char *data, int loc) | ||||||
| 	{ | 	{ | ||||||
| 	char **s; | 	char **s; | ||||||
| 
 | 
 | ||||||
|  | 	if(st == NULL) return 0; | ||||||
| 	if (st->num_alloc <= st->num+1) | 	if (st->num_alloc <= st->num+1) | ||||||
| 		{ | 		{ | ||||||
| 		s=(char **)Realloc((char *)st->data, | 		s=(char **)Realloc((char *)st->data, | ||||||
|  | @ -183,7 +184,8 @@ char *sk_delete(STACK *st, int loc) | ||||||
| 	char *ret; | 	char *ret; | ||||||
| 	int i,j; | 	int i,j; | ||||||
| 
 | 
 | ||||||
| 	if ((st->num == 0) || (loc < 0) || (loc >= st->num)) return(NULL); | 	if ((st == NULL) || (st->num == 0) || (loc < 0) | ||||||
|  | 					 || (loc >= st->num)) return(NULL); | ||||||
| 
 | 
 | ||||||
| 	ret=st->data[loc]; | 	ret=st->data[loc]; | ||||||
| 	if (loc != st->num-1) | 	if (loc != st->num-1) | ||||||
|  | @ -206,6 +208,7 @@ int sk_find(STACK *st, char *data) | ||||||
| 	char **r; | 	char **r; | ||||||
| 	int i; | 	int i; | ||||||
| 	int (*comp_func)(); | 	int (*comp_func)(); | ||||||
|  | 	if(st == NULL) return -1; | ||||||
| 
 | 
 | ||||||
| 	if (st->comp == NULL) | 	if (st->comp == NULL) | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
|  | @ -96,6 +96,7 @@ STACK *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, | ||||||
| 		gen = sk_GENERAL_NAME_value(gens, i); | 		gen = sk_GENERAL_NAME_value(gens, i); | ||||||
| 		ret = i2v_GENERAL_NAME(method, gen, ret); | 		ret = i2v_GENERAL_NAME(method, gen, ret); | ||||||
| 	} | 	} | ||||||
|  | 	if(!ret) return sk_GENERAL_NAME_new_null(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,13 +71,16 @@ void X509V3_EXT_val_prn(BIO *out, STACK *val, int indent, int ml) | ||||||
| 	int i; | 	int i; | ||||||
| 	CONF_VALUE *nval; | 	CONF_VALUE *nval; | ||||||
| 	if(!val) return; | 	if(!val) return; | ||||||
| 	if(!ml) BIO_printf(out, "%*s", indent, ""); | 	if(!ml || !sk_num(val)) { | ||||||
|  | 		BIO_printf(out, "%*s", indent, ""); | ||||||
|  | 		if(!sk_num(val)) BIO_puts(out, "<EMPTY>\n"); | ||||||
|  | 	} | ||||||
| 	for(i = 0; i < sk_num(val); i++) { | 	for(i = 0; i < sk_num(val); i++) { | ||||||
| 		if(ml) BIO_printf(out, "%*s", indent, ""); | 		if(ml) BIO_printf(out, "%*s", indent, ""); | ||||||
| 		else if(i > 0) BIO_printf(out, ", "); | 		else if(i > 0) BIO_printf(out, ", "); | ||||||
| 		nval = (CONF_VALUE *)sk_value(val, i); | 		nval = (CONF_VALUE *)sk_value(val, i); | ||||||
| 		if(!nval->name) BIO_printf(out, "%s", nval->value); | 		if(!nval->name) BIO_puts(out, nval->value); | ||||||
| 		else if(!nval->value) BIO_printf(out, "%s", nval->name); | 		else if(!nval->value) BIO_puts(out, nval->name); | ||||||
| 		else BIO_printf(out, "%s:%s", nval->name, nval->value); | 		else BIO_printf(out, "%s:%s", nval->name, nval->value); | ||||||
| 		if(ml) BIO_puts(out, "\n"); | 		if(ml) BIO_puts(out, "\n"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										352
									
								
								doc/openssl.txt
								
								
								
								
							
							
						
						
									
										352
									
								
								doc/openssl.txt
								
								
								
								
							|  | @ -5,21 +5,17 @@ This is some preliminary documentation for OpenSSL. | ||||||
|                             BUFFER Library |                             BUFFER Library | ||||||
| ============================================================================== | ============================================================================== | ||||||
| 
 | 
 | ||||||
| [Note: I wrote this when I saw a Malloc version of strdup() in there which |  | ||||||
|  I'd written myself anyway. I was so annoyed at not noticing this I decided to |  | ||||||
|  document it :-) Steve.] |  | ||||||
| 
 |  | ||||||
| The buffer library handles simple character arrays. Buffers are used for various | The buffer library handles simple character arrays. Buffers are used for various | ||||||
| purposes in the library, most notably memory BIOs. | purposes in the library, most notably memory BIOs. | ||||||
| 
 | 
 | ||||||
| The library uses the BUF_MEM structure defined in buffer.h: | The library uses the BUF_MEM structure defined in buffer.h: | ||||||
| 
 | 
 | ||||||
| typedef struct buf_mem_st | typedef struct buf_mem_st | ||||||
|         { | { | ||||||
|         int length;     /* current number of bytes */ |         int length;     /* current number of bytes */ | ||||||
|         char *data; |         char *data; | ||||||
|         int max;        /* size of buffer */ |         int max;        /* size of buffer */ | ||||||
|         } BUF_MEM; | } BUF_MEM; | ||||||
| 
 | 
 | ||||||
| 'length' is the current size of the buffer in bytes, 'max' is the amount of | 'length' is the current size of the buffer in bytes, 'max' is the amount of | ||||||
| memory allocated to the buffer. There are three functions which handle these | memory allocated to the buffer. There are three functions which handle these | ||||||
|  | @ -186,8 +182,7 @@ Literal String extensions. | ||||||
| 
 | 
 | ||||||
| In each case the 'value' of the extension is placed directly in the extension. | In each case the 'value' of the extension is placed directly in the extension. | ||||||
| Currently supported extensions in this category are: nsBaseUrl, nsRevocationUrl | Currently supported extensions in this category are: nsBaseUrl, nsRevocationUrl | ||||||
| nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl, nsSslServerName and | nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl, nsSslServerName and nsComment. | ||||||
| nsComment. |  | ||||||
| 
 | 
 | ||||||
| For example: | For example: | ||||||
| 
 | 
 | ||||||
|  | @ -227,7 +222,7 @@ basicConstraints=critical,CA:TRUE, pathlen:10 | ||||||
| 
 | 
 | ||||||
| NOTE: for a CA to be considered valid it must have the CA option set to | NOTE: for a CA to be considered valid it must have the CA option set to | ||||||
| TRUE. An end user certificate MUST NOT have the CA value set to true. | TRUE. An end user certificate MUST NOT have the CA value set to true. | ||||||
| According to PKIX recommendations it should exclude the extension entirely | According to PKIX recommendations it should exclude the extension entirely, | ||||||
| however some software may require CA set to FALSE for end entity certificates. | however some software may require CA set to FALSE for end entity certificates. | ||||||
| 
 | 
 | ||||||
| Subject Key Identifier. | Subject Key Identifier. | ||||||
|  | @ -355,3 +350,342 @@ Some extensions are only partially supported and currently are only displayed | ||||||
| but cannot be set. These include private key usage period, CRL number, and | but cannot be set. These include private key usage period, CRL number, and | ||||||
| CRL reason. | CRL reason. | ||||||
| 
 | 
 | ||||||
|  | ============================================================================== | ||||||
|  |                             PKCS#12 Library | ||||||
|  | ============================================================================== | ||||||
|  | 
 | ||||||
|  | This section describes the internal PKCS#12 support. There are very few | ||||||
|  | differences between the old external library and the new internal code at | ||||||
|  | present. This may well change because the external library will not be updated | ||||||
|  | much in future. | ||||||
|  | 
 | ||||||
|  | This version now includes a couple of high level PKCS#12 functions which | ||||||
|  | generally "do the right thing" and should make it much easier to handle PKCS#12 | ||||||
|  | structures. | ||||||
|  | 
 | ||||||
|  | HIGH LEVEL FUNCTIONS. | ||||||
|  | 
 | ||||||
|  | For most applications you only need concern yourself with the high level | ||||||
|  | functions. They can parse and generate simple PKCS#12 files as produced by | ||||||
|  | Netscape and MSIE or indeed any compliant PKCS#12 file containing a single | ||||||
|  | private key and certificate pair. | ||||||
|  | 
 | ||||||
|  | 1. Initialisation and cleanup. | ||||||
|  | 
 | ||||||
|  | No special initialisation is needed for the internal PKCS#12 library: the  | ||||||
|  | standard SSLeay_add_all_algorithms() is sufficient. If you do not wish to | ||||||
|  | add all algorithms then you can manually initialise the PKCS#12 library with: | ||||||
|  | 
 | ||||||
|  | PKSC12_PBE_add(); | ||||||
|  | 
 | ||||||
|  | The memory allocated by the PKCS#12 libray is freed up when EVP_cleanup() is | ||||||
|  | called or it can be directly freed with: | ||||||
|  | 
 | ||||||
|  | EVP_PBE_cleanup(); | ||||||
|  | 
 | ||||||
|  | after this call (or EVP_cleanup() ) no more PKCS#12 library functions should | ||||||
|  | be called. | ||||||
|  | 
 | ||||||
|  | 2. I/O functions. | ||||||
|  | 
 | ||||||
|  | i2d_PKCS12_bio(bp, p12) | ||||||
|  | 
 | ||||||
|  | This writes out a PKCS12 structure to a BIO. | ||||||
|  | 
 | ||||||
|  | i2d_PKCS12_fp(fp, p12) | ||||||
|  | 
 | ||||||
|  | This is the same but for a FILE pointer. | ||||||
|  | 
 | ||||||
|  | d2i_PKCS12_bio(bp, p12) | ||||||
|  | 
 | ||||||
|  | This reads in a PKCS12 structure from a BIO. | ||||||
|  | 
 | ||||||
|  | d2i_PKCS12_fp(fp, p12) | ||||||
|  | 
 | ||||||
|  | This is the same but for a FILE pointer. | ||||||
|  | 
 | ||||||
|  | 3. Parsing and creation functions. | ||||||
|  | 
 | ||||||
|  | 3.1 Parsing with PKCS12_parse(). | ||||||
|  | 
 | ||||||
|  | int PKCS12_parse(PKCS12 *p12, char *pass, EVP_PKEY **pkey, X509 **cert, | ||||||
|  | 								 STACK **ca); | ||||||
|  | 
 | ||||||
|  | This function takes a PKCS12 structure and a password (ASCII, null terminated) | ||||||
|  | and returns the private key, the corresponding certificate and any CA | ||||||
|  | certificates. If any of these is not required it can be passed as a NULL. | ||||||
|  | The 'ca' parameter should be either NULL, a pointer to NULL or a valid STACK | ||||||
|  | structure. Typically to read in a PKCS#12 file you might do: | ||||||
|  | 
 | ||||||
|  | p12 = d2i_PKCS12_fp(fp, NULL); | ||||||
|  | PKCS12_parse(p12, password, &pkey, &cert, NULL); 	/* CAs not wanted */ | ||||||
|  | PKCS12_free(p12); | ||||||
|  | 
 | ||||||
|  | 3.2 PKCS#12 creation with PKCS12_create(). | ||||||
|  | 
 | ||||||
|  | PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, | ||||||
|  | 			STACK *ca, int nid_key, int nid_cert, int iter, | ||||||
|  | 						 int mac_iter, int keytype); | ||||||
|  | 
 | ||||||
|  | This function will create a PKCS12 structure from a given password, name, | ||||||
|  | private key, certificate and optional STACK of CA certificates. The remaining | ||||||
|  | 5 parameters can be set to 0 and sensible defaults will be used. | ||||||
|  | 
 | ||||||
|  | The parameters nid_key and nid_cert are the key and certificate encryption | ||||||
|  | algorithms, iter is the encryption iteration count, mac_iter is the MAC | ||||||
|  | iteration count and keytype is the type of private key. If you really want | ||||||
|  | to know what these last 5 parameters do then read the low level section. | ||||||
|  | 
 | ||||||
|  | Typically to create a PKCS#12 file the following could be used: | ||||||
|  | 
 | ||||||
|  | p12 = PKCS12_create(pass, "My Certificate", pkey, cert, NULL, 0,0,0,0,0); | ||||||
|  | i2d_PKCS12_fp(fp, p12); | ||||||
|  | PKCS12_free(p12); | ||||||
|  | 
 | ||||||
|  | LOW LEVEL FUNCTIONS. | ||||||
|  | 
 | ||||||
|  | In some cases the high level functions do not provide the necessary | ||||||
|  | functionality. For example if you want to generate or parse more complex PKCS#12 | ||||||
|  | files. The sample pkcs12 application uses the low level functions to display | ||||||
|  | details about the internal structure of a PKCS#12 file. | ||||||
|  | 
 | ||||||
|  | Introduction. | ||||||
|  | 
 | ||||||
|  | This is a brief description of how a PKCS#12 file is represented internally: | ||||||
|  | some knowledge of PKCS#12 is assumed. | ||||||
|  | 
 | ||||||
|  | A PKCS#12 object contains several levels. | ||||||
|  | 
 | ||||||
|  | At the lowest level is a PKCS12_SAFEBAG. This can contain a certificate, a | ||||||
|  | CRL, a private key, encrypted or unencrypted, a set of safebags (so the | ||||||
|  | structure can be nested) or other secrets (not documented at present).  | ||||||
|  | A safebag can optionally have attributes, currently these are: a unicode | ||||||
|  | friendlyName (a Unicode string) or a localKeyID (a string of bytes). | ||||||
|  | 
 | ||||||
|  | At the next level is an authSafe which is a set of safebags collected into | ||||||
|  | a PKCS#7 ContentInfo. This can be just plain data, or encrypted itself. | ||||||
|  | 
 | ||||||
|  | At the top level is the PKCS12 structure itself which contains a set of | ||||||
|  | authSafes in an embedded PKCS#7 Contentinfo of type data. In addition it | ||||||
|  | contains a MAC which is a kind of password protected digest to preserve | ||||||
|  | integrity (so any unencrypted stuff below can't be tampered with). | ||||||
|  | 
 | ||||||
|  | The reason for these levels is so various objects can be encrypted in various | ||||||
|  | ways. For example you might want to encrypt a set of private keys with | ||||||
|  | triple-DES and then include the related certificates either unencrypted or with | ||||||
|  | lower encryption. Yes it's the dreaded crypto laws at work again which | ||||||
|  | allow strong encryption on private keys and only weak encryption on other stuff. | ||||||
|  | 
 | ||||||
|  | To build one of these things you turn all certificates and keys into safebags | ||||||
|  | (with optional attributes). You collect the safebags into (one or more) STACKS | ||||||
|  | and convert these into authsafes (encrypted or unencrypted).  The authsafes are | ||||||
|  | collected into a STACK and added to a PKCS12 structure.  Finally a MAC inserted. | ||||||
|  | 
 | ||||||
|  | Pulling one apart is basically the reverse process. The MAC is verified against | ||||||
|  | the given password. The authsafes are extracted and each authsafe split into | ||||||
|  | a set of safebags (possibly involving decryption). Finally the safebags are | ||||||
|  | decomposed into the original keys and certificates and the attributes used to | ||||||
|  | match up private key and certificate pairs. | ||||||
|  | 
 | ||||||
|  | Anyway here are the functions that do the dirty work. | ||||||
|  | 
 | ||||||
|  | 1. Construction functions. | ||||||
|  | 
 | ||||||
|  | 1.1 Safebag functions. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_x5092certbag(x509) | ||||||
|  | 
 | ||||||
|  | This macro takes an X509 structure and returns a certificate bag. The | ||||||
|  | X509 structure can be freed up after calling this function. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_x509crl2certbag(crl) | ||||||
|  | 
 | ||||||
|  | As above but for a CRL. | ||||||
|  | 
 | ||||||
|  | PKCS8_PRIV_KEY_INFO *PKEY2PKCS8(EVP_PKEY *pkey) | ||||||
|  | 
 | ||||||
|  | Take a private key and convert it into a PKCS#8 PrivateKeyInfo structure. | ||||||
|  | Works for both RSA and DSA private keys. NB since the PKCS#8 PrivateKeyInfo | ||||||
|  | structure contains a private key data in plain text form it should be free'd up | ||||||
|  | as soon as it has been encrypted for security reasons (freeing up the structure | ||||||
|  | zeros out the sensitive data). This can be done with PKCS8_PRIV_KEY_INFO_free(). | ||||||
|  | 
 | ||||||
|  | PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage) | ||||||
|  | 
 | ||||||
|  | This sets the key type when a key is imported into MSIE or Outlook 98. Two | ||||||
|  | values are currently supported: KEY_EX and KEY_SIG. KEY_EX is an exchange type | ||||||
|  | key that can also be used for signing but its size is limited in the export | ||||||
|  | versions of MS software to 512 bits, it is also the default. KEY_SIG is a | ||||||
|  | signing only key but the keysize is unlimited (well 16K is supposed to work). | ||||||
|  | If you are using the domestic version of MSIE then you can ignore this because | ||||||
|  | KEY_EX is not limited and can be used for both. | ||||||
|  | 
 | ||||||
|  | PKCS12_SAFEBAG *PKCS12_MAKE_KEYBAG(PKCS8_PRIV_KEY_INFO *p8) | ||||||
|  | 
 | ||||||
|  | Convert a PKCS8 private key structure into a keybag. This routine embeds the p8 | ||||||
|  | structure in the keybag so p8 should not be freed up or used after it is called. | ||||||
|  | The p8 structure will be freed up when the safebag is freed. | ||||||
|  | 
 | ||||||
|  | PKCS12_SAFEBAG *PKCS12_MAKE_SHKEYBAG(int pbe_nid, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, PKCS8_PRIV_KEY_INFO *p8) | ||||||
|  | 
 | ||||||
|  | Convert a PKCS#8 structure into a shrouded key bag (encrypted). p8 is not | ||||||
|  | embedded and can be freed up after use. | ||||||
|  | 
 | ||||||
|  | int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen) | ||||||
|  | int PKCS12_add_friendlyname(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen) | ||||||
|  | 
 | ||||||
|  | Add a local key id or a friendlyname to a safebag. | ||||||
|  | 
 | ||||||
|  | 1.2 Authsafe functions. | ||||||
|  | 
 | ||||||
|  | PKCS7 *PKCS12_pack_p7data(STACK *sk) | ||||||
|  | Take a stack of safebags and convert them into an unencrypted authsafe. The | ||||||
|  | stack of safebags can be freed up after calling this function. | ||||||
|  | 
 | ||||||
|  | PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, STACK *bags); | ||||||
|  | 
 | ||||||
|  | As above but encrypted. | ||||||
|  | 
 | ||||||
|  | 1.3 PKCS12 functions. | ||||||
|  | 
 | ||||||
|  | PKCS12 *PKCS12_init(int mode) | ||||||
|  | 
 | ||||||
|  | Initialise a PKCS12 structure (currently mode should be NID_pkcs7_data). | ||||||
|  | 
 | ||||||
|  | M_PKCS12_pack_authsafes(p12, safes) | ||||||
|  | 
 | ||||||
|  | This macro takes a STACK of authsafes and adds them to a PKCS#12 structure. | ||||||
|  | 
 | ||||||
|  | int PKCS12_set_mac(PKCS12 *p12, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, EVP_MD *md_type); | ||||||
|  | 
 | ||||||
|  | Add a MAC to a PKCS12 structure. If EVP_MD is NULL use SHA-1, the spec suggests | ||||||
|  | that SHA-1 should be used. | ||||||
|  | 
 | ||||||
|  | 2. Extraction Functions. | ||||||
|  | 
 | ||||||
|  | 2.1 Safebags. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_bag_type(bag) | ||||||
|  | 
 | ||||||
|  | Return the type of "bag". Returns one of the following | ||||||
|  | 
 | ||||||
|  | NID_keyBag | ||||||
|  | NID_pkcs8ShroudedKeyBag			7 | ||||||
|  | NID_certBag				8 | ||||||
|  | NID_crlBag				9 | ||||||
|  | NID_secretBag				10 | ||||||
|  | NID_safeContentsBag			11 | ||||||
|  | 
 | ||||||
|  | M_PKCS12_cert_bag_type(bag) | ||||||
|  | 
 | ||||||
|  | Returns type of certificate bag, following are understood. | ||||||
|  | 
 | ||||||
|  | NID_x509Certificate			14 | ||||||
|  | NID_sdsiCertificate			15 | ||||||
|  | 
 | ||||||
|  | M_PKCS12_crl_bag_type(bag) | ||||||
|  | 
 | ||||||
|  | Returns crl bag type, currently only NID_crlBag is recognised. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_certbag2x509(bag) | ||||||
|  | 
 | ||||||
|  | This macro extracts an X509 certificate from a certificate bag. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_certbag2x509crl(bag) | ||||||
|  | 
 | ||||||
|  | As above but for a CRL. | ||||||
|  | 
 | ||||||
|  | EVP_PKEY * PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) | ||||||
|  | 
 | ||||||
|  | Extract a private key from a PKCS8 private key info structure. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_decrypt_skey(bag, pass, passlen)  | ||||||
|  | 
 | ||||||
|  | Decrypt a shrouded key bag and return a PKCS8 private key info structure. | ||||||
|  | Works with both RSA and DSA keys | ||||||
|  | 
 | ||||||
|  | char *PKCS12_get_friendlyname(bag) | ||||||
|  | 
 | ||||||
|  | Returns the friendlyName of a bag if present or NULL if none. The returned | ||||||
|  | string is a null terminated ASCII string allocated with Malloc(). It should  | ||||||
|  | thus be freed up with Free() after use. | ||||||
|  | 
 | ||||||
|  | 2.2 AuthSafe functions. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_unpack_p7data(p7) | ||||||
|  | 
 | ||||||
|  | Extract a STACK of safe bags from a PKCS#7 data ContentInfo. | ||||||
|  | 
 | ||||||
|  | #define M_PKCS12_unpack_p7encdata(p7, pass, passlen) | ||||||
|  | 
 | ||||||
|  | As above but for an encrypted content info. | ||||||
|  | 
 | ||||||
|  | 2.3 PKCS12 functions. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_unpack_authsafes(p12) | ||||||
|  | 
 | ||||||
|  | Extract a STACK of authsafes from a PKCS12 structure. | ||||||
|  | 
 | ||||||
|  | M_PKCS12_mac_present(p12) | ||||||
|  | 
 | ||||||
|  | Check to see if a MAC is present. | ||||||
|  | 
 | ||||||
|  | int PKCS12_verify_mac(PKCS12 *p12, unsigned char *pass, int passlen) | ||||||
|  | 
 | ||||||
|  | Verify a MAC on a PKCS12 structure. Returns an error if MAC not present. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Notes. | ||||||
|  | 
 | ||||||
|  | 1. All the function return 0 or NULL on error. | ||||||
|  | 2. Encryption based functions take a common set of parameters. These are | ||||||
|  | described below. | ||||||
|  | 
 | ||||||
|  | pass, passlen | ||||||
|  | ASCII password and length. The password on the MAC is called the "integrity | ||||||
|  | password" the encryption password is called the "privacy password" in the | ||||||
|  | PKCS#12 documentation. The passwords do not have to be the same. If -1 is | ||||||
|  | passed for the length it is worked out by the function itself (currently | ||||||
|  | this is sometimes done whatever is passed as the length but that may change). | ||||||
|  | 
 | ||||||
|  | salt, saltlen | ||||||
|  | A 'salt' if salt is NULL a random salt is used. If saltlen is also zero a | ||||||
|  | default length is used. | ||||||
|  | 
 | ||||||
|  | iter | ||||||
|  | Iteration count. This is a measure of how many times an internal function is | ||||||
|  | called to encrypt the data. The larger this value is the longer it takes, it | ||||||
|  | makes dictionary attacks on passwords harder. NOTE: Some implementations do | ||||||
|  | not support an iteration count on the MAC. If the password for the MAC and | ||||||
|  | encryption is the same then there is no point in having a high iteration | ||||||
|  | count for encryption if the MAC has no count. The MAC could be attacked | ||||||
|  | and the password used for the main decryption. | ||||||
|  | 
 | ||||||
|  | pbe_nid | ||||||
|  | This is the NID of the password based encryption method used. The following are | ||||||
|  | supported. | ||||||
|  | NID_pbe_WithSHA1And128BitRC4 | ||||||
|  | NID_pbe_WithSHA1And40BitRC4 | ||||||
|  | NID_pbe_WithSHA1And3_Key_TripleDES_CBC | ||||||
|  | NID_pbe_WithSHA1And2_Key_TripleDES_CBC | ||||||
|  | NID_pbe_WithSHA1And128BitRC2_CBC | ||||||
|  | NID_pbe_WithSHA1And40BitRC2_CBC | ||||||
|  | 
 | ||||||
|  | Which you use depends on the implementation you are exporting to. "Export grade"(i.e. cryptograhically challenged) products cannot support all algorithms. | ||||||
|  | Typically you may be able to use any encryption on shrouded key bags but they | ||||||
|  | must then be placed in an unencrypted authsafe. Other authsafes may only support | ||||||
|  | 40bit encryption. Of course if you are using SSLeay throughout you can strongly | ||||||
|  | encrypt everything and have high iteration counts on everything. | ||||||
|  | 
 | ||||||
|  | 3. For decryption routines only the password and length are needed. | ||||||
|  | 
 | ||||||
|  | 4. Unlike the external version the nid's of objects are the values of the | ||||||
|  | constants: that is NID_certBag is the real nid, therefore there is no  | ||||||
|  | PKCS12_obj_offset() function.  Note the object constants are not the same as | ||||||
|  | those of the external version. If you use these constants then you will need | ||||||
|  | to recompile your code. | ||||||
|  | 
 | ||||||
|  | 5. With the exception of PKCS12_MAKE_KEYBAG(), after calling any function or  | ||||||
|  | macro of the form PKCS12_MAKE_SOMETHING(other) the "other" structure can be | ||||||
|  | reused or freed up safely. | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue