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…
x
Reference in New Issue
Block a user