From: Dr. Stephen Henson Date: Tue, 27 Apr 1999 00:36:20 +0000 (+0000) Subject: Add PKCS#12 documentation and new option in x509 to add certificate extensions. X-Git-Tag: OpenSSL_0_9_3beta1~231 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=b64f825671861144e1c24f2a5498a95a083021cd;p=oweals%2Fopenssl.git Add PKCS#12 documentation and new option in x509 to add certificate extensions. --- diff --git a/CHANGES b/CHANGES index ca68c8156d..61c31e2af4 100644 --- a/CHANGES +++ b/CHANGES @@ -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] diff --git a/STATUS b/STATUS index 6842a2719f..ec13da99d6 100644 --- a/STATUS +++ b/STATUS @@ -1,6 +1,6 @@ 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 diff --git a/apps/x509.c b/apps/x509.c index 01fabbb4bf..210a25fb09 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -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: diff --git a/crypto/evp/evp_pbe.c b/crypto/evp/evp_pbe.c index 02ae151cf4..848edddd8c 100644 --- a/crypto/evp/evp_pbe.c +++ b/crypto/evp/evp_pbe.c @@ -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; } diff --git a/crypto/stack/stack.c b/crypto/stack/stack.c index 242337a391..5a15a2456d 100644 --- a/crypto/stack/stack.c +++ b/crypto/stack/stack.c @@ -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) { diff --git a/crypto/x509v3/v3_alt.c b/crypto/x509v3/v3_alt.c index 99026fc8bc..e66a0748fd 100644 --- a/crypto/x509v3/v3_alt.c +++ b/crypto/x509v3/v3_alt.c @@ -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; } diff --git a/crypto/x509v3/v3_prn.c b/crypto/x509v3/v3_prn.c index 06a4f6964f..08e6e2cc6e 100644 --- a/crypto/x509v3/v3_prn.c +++ b/crypto/x509v3/v3_prn.c @@ -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, "\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"); } diff --git a/doc/openssl.txt b/doc/openssl.txt index e42cbbfef6..76f49132f0 100644 --- a/doc/openssl.txt +++ b/doc/openssl.txt @@ -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. +