提交 b64f8256 编写于 作者: D Dr. Stephen Henson

Add PKCS#12 documentation and new option in x509 to add certificate extensions.

上级 73d2257d
......@@ -5,6 +5,10 @@
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.
[Ulf Möller]
......
OpenSSL STATUS Last modified at
______________ $Date: 1999/04/26 20:56:18 $
______________ $Date: 1999/04/27 00:36:14 $
DEVELOPMENT STATE
......@@ -43,7 +43,6 @@
PKCS#12 code cleanup and enhancement.
PKCS #8 and PKCS#5 v2.0 support.
Private key, certificate and CRL API and implementation.
Redo error code and DEF file generation scripts.
o Mark is currently working on:
Folding in any changes that are in the C2Net code base that were
......
......@@ -114,16 +114,18 @@ static char *x509_usage[]={
" -text - print the certificate in text form\n",
" -C - print out C code forms\n",
" -md2/-md5/-sha1/-mdc2 - digest to do an RSA sign with\n",
" -config - configuration file with X509V3 extensions to add\n",
NULL
};
static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx);
static EVP_PKEY *load_key(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,
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;
int MAIN(int argc, char **argv)
......@@ -148,6 +150,8 @@ int MAIN(int argc, char **argv)
int fingerprint=0;
char buf[256];
const EVP_MD *md_alg,*digest=EVP_md5();
LHASH *extconf = NULL;
char *extsect = NULL, *extfile = NULL;
reqfile=0;
......@@ -209,6 +213,11 @@ int MAIN(int argc, char **argv)
goto bad;
}
}
else if (strcmp(*argv,"-config") == 0)
{
if (--argc < 1) goto bad;
extfile= *(++argv);
}
else if (strcmp(*argv,"-in") == 0)
{
if (--argc < 1) goto bad;
......@@ -312,6 +321,34 @@ bad:
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)
{
EVP_PKEY *pkey;
......@@ -589,7 +626,8 @@ bad:
digest=EVP_dss1();
#endif
if (!sign(x,Upkey,days,digest)) goto end;
if (!sign(x,Upkey,days,digest,
extconf, extsect)) goto end;
}
else if (CA_flag == i)
{
......@@ -605,8 +643,8 @@ bad:
#endif
if (!x509_certify(ctx,CAfile,digest,x,xca,
CApkey,
CAserial,CA_createserial,days))
CApkey, CAserial,CA_createserial,days,
extconf, extsect))
goto end;
}
else if (x509req == i)
......@@ -680,22 +718,23 @@ bad:
ret=0;
end:
OBJ_cleanup();
if (out != NULL) BIO_free(out);
if (STDout != NULL) BIO_free(STDout);
if (ctx != NULL) X509_STORE_free(ctx);
if (req != NULL) X509_REQ_free(req);
if (x != NULL) X509_free(x);
if (xca != NULL) X509_free(xca);
if (Upkey != NULL) EVP_PKEY_free(Upkey);
if (CApkey != NULL) EVP_PKEY_free(CApkey);
if (rq != NULL) X509_REQ_free(rq);
CONF_free(extconf);
BIO_free(out);
BIO_free(STDout);
X509_STORE_free(ctx);
X509_REQ_free(req);
X509_free(x);
X509_free(xca);
EVP_PKEY_free(Upkey);
EVP_PKEY_free(CApkey);
X509_REQ_free(rq);
X509V3_EXT_cleanup();
EXIT(ret);
}
static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
X509 *x, X509 *xca, EVP_PKEY *pkey, char *serialfile, int create,
int days)
int days, LHASH *conf, char *section)
{
int ret=0;
BIO *io=NULL;
......@@ -828,6 +867,14 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
}
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;
ret=1;
end:
......@@ -1014,7 +1061,8 @@ end:
}
/* 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;
......@@ -1035,6 +1083,13 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, const EVP_MD *digest)
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;
return(1);
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];
int i;
pbelu.pbe_nid = OBJ_obj2nid(pbe_obj);
if ((pbelu.pbe_nid != NID_undef) && pbe_algs)
i = sk_find (pbe_algs, (char *)&pbelu);
if (pbelu.pbe_nid != NID_undef) i = sk_find(pbe_algs, (char *)&pbelu);
else 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)
{
sk_pop_free(pbe_algs, FreeFunc);
pbe_algs = NULL;
}
......@@ -135,6 +135,7 @@ int sk_insert(STACK *st, char *data, int loc)
{
char **s;
if(st == NULL) return 0;
if (st->num_alloc <= st->num+1)
{
s=(char **)Realloc((char *)st->data,
......@@ -183,7 +184,8 @@ char *sk_delete(STACK *st, int loc)
char *ret;
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];
if (loc != st->num-1)
......@@ -206,6 +208,7 @@ int sk_find(STACK *st, char *data)
char **r;
int i;
int (*comp_func)();
if(st == NULL) return -1;
if (st->comp == NULL)
{
......
......@@ -96,6 +96,7 @@ STACK *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
gen = sk_GENERAL_NAME_value(gens, i);
ret = i2v_GENERAL_NAME(method, gen, ret);
}
if(!ret) return sk_GENERAL_NAME_new_null();
return ret;
}
......
......@@ -71,13 +71,16 @@ void X509V3_EXT_val_prn(BIO *out, STACK *val, int indent, int ml)
int i;
CONF_VALUE *nval;
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++) {
if(ml) BIO_printf(out, "%*s", indent, "");
else if(i > 0) BIO_printf(out, ", ");
nval = (CONF_VALUE *)sk_value(val, i);
if(!nval->name) BIO_printf(out, "%s", nval->value);
else if(!nval->value) BIO_printf(out, "%s", nval->name);
if(!nval->name) BIO_puts(out, nval->value);
else if(!nval->value) BIO_puts(out, nval->name);
else BIO_printf(out, "%s:%s", nval->name, nval->value);
if(ml) BIO_puts(out, "\n");
}
......
......@@ -5,21 +5,17 @@ This is some preliminary documentation for OpenSSL.
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
purposes in the library, most notably memory BIOs.
The library uses the BUF_MEM structure defined in buffer.h:
typedef struct buf_mem_st
{
{
int length; /* current number of bytes */
char *data;
int max; /* size of buffer */
} BUF_MEM;
} BUF_MEM;
'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
......@@ -186,8 +182,7 @@ Literal String extensions.
In each case the 'value' of the extension is placed directly in the extension.
Currently supported extensions in this category are: nsBaseUrl, nsRevocationUrl
nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl, nsSslServerName and
nsComment.
nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl, nsSslServerName and nsComment.
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
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.
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
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.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册