diff options
author | Ralf S. Engelschall <rse@openssl.org> | 1998-12-21 10:52:47 +0000 |
---|---|---|
committer | Ralf S. Engelschall <rse@openssl.org> | 1998-12-21 10:52:47 +0000 |
commit | d02b48c63a58ea4367a0e905979f140b7d090f86 (patch) | |
tree | 504f62ed3d84799f785b9cd9fab255a21b0e1b0e /doc | |
download | openssl-new-d02b48c63a58ea4367a0e905979f140b7d090f86.tar.gz |
Import of old SSLeay release: SSLeay 0.8.1b
Diffstat (limited to 'doc')
-rw-r--r-- | doc/API.doc | 24 | ||||
-rw-r--r-- | doc/a_verify.doc | 85 | ||||
-rw-r--r-- | doc/apps.doc | 53 | ||||
-rw-r--r-- | doc/asn1.doc | 401 | ||||
-rw-r--r-- | doc/bio.doc | 423 | ||||
-rw-r--r-- | doc/blowfish.doc | 149 | ||||
-rw-r--r-- | doc/bn.doc | 379 | ||||
-rw-r--r-- | doc/ca.1 | 121 | ||||
-rw-r--r-- | doc/callback.doc | 240 | ||||
-rw-r--r-- | doc/cipher.doc | 345 | ||||
-rw-r--r-- | doc/cipher.m | 128 | ||||
-rw-r--r-- | doc/conf.doc | 89 | ||||
-rw-r--r-- | doc/danger | 8 | ||||
-rw-r--r-- | doc/des.doc | 505 | ||||
-rw-r--r-- | doc/digest.doc | 94 | ||||
-rw-r--r-- | doc/encode.doc | 15 | ||||
-rw-r--r-- | doc/envelope.doc | 67 | ||||
-rw-r--r-- | doc/error.doc | 115 | ||||
-rw-r--r-- | doc/idea.doc | 176 | ||||
-rw-r--r-- | doc/legal.doc | 117 | ||||
-rw-r--r-- | doc/lhash.doc | 151 | ||||
-rw-r--r-- | doc/md2.doc | 49 | ||||
-rw-r--r-- | doc/md5.doc | 50 | ||||
-rw-r--r-- | doc/memory.doc | 27 | ||||
-rw-r--r-- | doc/ms3-ca.doc | 398 | ||||
-rw-r--r-- | doc/ns-ca.doc | 154 | ||||
-rw-r--r-- | doc/obj.doc | 69 | ||||
-rw-r--r-- | doc/rand.doc | 141 | ||||
-rw-r--r-- | doc/rc2.doc | 165 | ||||
-rw-r--r-- | doc/rc4.doc | 44 | ||||
-rw-r--r-- | doc/readme | 6 | ||||
-rw-r--r-- | doc/ref.doc | 48 | ||||
-rw-r--r-- | doc/req.1 | 137 | ||||
-rw-r--r-- | doc/rsa.doc | 133 | ||||
-rw-r--r-- | doc/rsaref.doc | 35 | ||||
-rw-r--r-- | doc/s_mult.doc | 17 | ||||
-rw-r--r-- | doc/session.doc | 297 | ||||
-rw-r--r-- | doc/sha.doc | 52 | ||||
-rw-r--r-- | doc/speed.doc | 96 | ||||
-rw-r--r-- | doc/ssl-ciph.doc | 84 | ||||
-rw-r--r-- | doc/ssl.doc | 172 | ||||
-rw-r--r-- | doc/ssl_ctx.doc | 68 | ||||
-rw-r--r-- | doc/ssleay.doc | 213 | ||||
-rw-r--r-- | doc/ssluse.doc | 45 | ||||
-rw-r--r-- | doc/stack.doc | 96 | ||||
-rw-r--r-- | doc/threads.doc | 90 | ||||
-rw-r--r-- | doc/txt_db.doc | 4 | ||||
-rw-r--r-- | doc/verify | 22 | ||||
-rw-r--r-- | doc/why.doc | 79 |
49 files changed, 6476 insertions, 0 deletions
diff --git a/doc/API.doc b/doc/API.doc new file mode 100644 index 0000000000..fe2820259a --- /dev/null +++ b/doc/API.doc @@ -0,0 +1,24 @@ +SSL - SSLv2/v3/v23 etc. + +BIO - methods and how they plug together + +MEM - memory allocation callback + +CRYPTO - locking for threads + +EVP - Ciphers/Digests/signatures + +RSA - methods + +X509 - certificate retrieval + +X509 - validation + +X509 - X509v3 extensions + +Objects - adding object identifiers + +ASN.1 - parsing + +PEM - parsing + diff --git a/doc/a_verify.doc b/doc/a_verify.doc new file mode 100644 index 0000000000..06eec17c2b --- /dev/null +++ b/doc/a_verify.doc @@ -0,0 +1,85 @@ +From eay@mincom.com Fri Oct 4 18:29:06 1996 +Received: by orb.mincom.oz.au id AA29080 + (5.65c/IDA-1.4.4 for eay); Fri, 4 Oct 1996 08:29:07 +1000 +Date: Fri, 4 Oct 1996 08:29:06 +1000 (EST) +From: Eric Young <eay@mincom.oz.au> +X-Sender: eay@orb +To: wplatzer <wplatzer@iaik.tu-graz.ac.at> +Cc: Eric Young <eay@mincom.oz.au>, SSL Mailing List <ssl-users@mincom.com> +Subject: Re: Netscape's Public Key +In-Reply-To: <19961003134837.NTM0049@iaik.tu-graz.ac.at> +Message-Id: <Pine.SOL.3.91.961004081346.8018K-100000@orb> +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Status: RO +X-Status: + +On Thu, 3 Oct 1996, wplatzer wrote: +> I get Public Key from Netscape (Gold 3.0b4), but cannot do anything +> with it... It looks like (asn1parse): +> +> 0:d=0 hl=3 l=180 cons: SEQUENCE +> 3:d=1 hl=2 l= 96 cons: SEQUENCE +> 5:d=2 hl=2 l= 92 cons: SEQUENCE +> 7:d=3 hl=2 l= 13 cons: SEQUENCE +> 9:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption +> 20:d=4 hl=2 l= 0 prim: NULL +> 22:d=3 hl=2 l= 75 prim: BIT STRING +> 99:d=2 hl=2 l= 0 prim: IA5STRING : +> 101:d=1 hl=2 l= 13 cons: SEQUENCE +> 103:d=2 hl=2 l= 9 prim: OBJECT :md5withRSAEncryption +> 114:d=2 hl=2 l= 0 prim: NULL +> 116:d=1 hl=2 l= 65 prim: BIT STRING +> +> The first BIT STRING is the public key and the second BIT STRING is +> the signature. +> But a public key consists of the public exponent and the modulus. Are +> both numbers in the first BIT STRING? +> Is there a document simply describing this coding stuff (checking +> signature, get the public key, etc.)? + +Minimal in SSLeay. If you want to see what the modulus and exponent are, +try asn1parse -offset 25 -length 75 <key.pem +asn1parse will currently stuff up on the 'length 75' part (fixed in next +release) but it will print the stuff. If you are after more +documentation on ASN.1, have a look at www.rsa.com and get their PKCS +documents, most of my initial work on SSLeay was done using them. + +As for SSLeay, +util/crypto.num and util/ssl.num are lists of all exported functions in +the library (but not macros :-(. + +The ones for extracting public keys from certificates and certificate +requests are EVP_PKEY * X509_REQ_extract_key(X509_REQ *req); +EVP_PKEY * X509_extract_key(X509 *x509); + +To verify a signature on a signed ASN.1 object +int X509_verify(X509 *a,EVP_PKEY *key); +int X509_REQ_verify(X509_REQ *a,EVP_PKEY *key); +int X509_CRL_verify(X509_CRL *a,EVP_PKEY *key); +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a,EVP_PKEY *key); + +I should mention that EVP_PKEY can be used to hold a public or a private key, +since for things like RSA and DSS, a public key is just a subset of what +is stored for the private key. + +To sign any of the above structures + +int X509_sign(X509 *a,EVP_PKEY *key,EVP_MD *md); +int X509_REQ_sign(X509_REQ *a,EVP_PKEY *key,EVP_MD *md); +int X509_CRL_sign(X509_CRL *a,EVP_PKEY *key,EVP_MD *md); +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *a,EVP_PKEY *key,EVP_MD *md); + +where md is the message digest to sign with. + +There are all defined in x509.h and all the _sign and _verify functions are +actually macros to the ASN1_sign() and ASN1_verify() functions. +These functions will put the correct algorithm identifiers in the correct +places in the structures. + +eric +-- +Eric Young | BOOL is tri-state according to Bill Gates. +AARNet: eay@mincom.oz.au | RTFM Win32 GetMessage(). + + diff --git a/doc/apps.doc b/doc/apps.doc new file mode 100644 index 0000000000..a2a4e0de72 --- /dev/null +++ b/doc/apps.doc @@ -0,0 +1,53 @@ +The applications + +Ok, where to begin.... +In the begining, when SSLeay was small (April 1995), there +were but few applications, they did happily cohabit in +the one bin directory. Then over time, they did multiply and grow, +and they started to look like microsoft software; 500k to print 'hello world'. +A new approach was needed. They were coalessed into one 'Monolithic' +application, ssleay. This one program is composed of many programs that +can all be compiled independantly. + +ssleay has 3 modes of operation. +1) If the ssleay binaray has the name of one of its component programs, it +executes that program and then exits. This can be achieve by using hard or +symbolic links, or failing that, just renaming the binary. +2) If the first argument to ssleay is the name of one of the component +programs, that program runs that program and then exits. +3) If there are no arguments, ssleay enters a 'command' mode. Each line is +interpreted as a program name plus arguments. After each 'program' is run, +ssleay returns to the comand line. + +dgst - message digests +enc - encryption and base64 encoding + +ans1parse - 'pulls' appart ASN.1 encoded objects like certificates. + +dh - Diffle-Hellman parameter manipulation. +rsa - RSA manipulations. +crl - Certificate revokion list manipulations +x509 - X509 cert fiddles, including signing. +pkcs7 - pkcs7 manipulation, only DER versions right now. + +genrsa - generate an RSA private key. +gendh - Generate a set of Diffle-Hellman parameters. +req - Generate a PKCS#10 object, a certificate request. + +s_client - SSL client program +s_server - SSL server program +s_time - A SSL protocol timing program +s_mult - Another SSL server, but it multiplexes + connections. +s_filter - under development + +errstr - Convert SSLeay error numbers to strings. +ca - Sign certificate requests, and generate + certificate revokion lists +crl2pkcs7 - put a crl and certifcates into a pkcs7 object. +speed - Benchmark the ciphers. +verify - Check certificates +hashdir - under development + +[ there a now a few more options, play with the program to see what they + are ] diff --git a/doc/asn1.doc b/doc/asn1.doc new file mode 100644 index 0000000000..fdad17c05c --- /dev/null +++ b/doc/asn1.doc @@ -0,0 +1,401 @@ +The ASN.1 Routines. + +ASN.1 is a specification for how to encode structured 'data' in binary form. +The approach I have take to the manipulation of structures and their encoding +into ASN.1 is as follows. + +For each distinct structure there are 4 function of the following form +TYPE *TYPE_new(void); +void TYPE_free(TYPE *); +TYPE *d2i_TYPE(TYPE **a,unsigned char **pp,long length); +long i2d_TYPE(TYPE *a,unsigned char **pp); /* CHECK RETURN VALUE */ + +where TYPE is the type of the 'object'. The TYPE that have these functions +can be in one of 2 forms, either the internal C malloc()ed data structure +or in the DER (a variant of ASN.1 encoding) binary encoding which is just +an array of unsigned bytes. The 'i2d' functions converts from the internal +form to the DER form and the 'd2i' functions convert from the DER form to +the internal form. + +The 'new' function returns a malloc()ed version of the structure with all +substructures either created or left as NULL pointers. For 'optional' +fields, they are normally left as NULL to indicate no value. For variable +size sub structures (often 'SET OF' or 'SEQUENCE OF' in ASN.1 syntax) the +STACK data type is used to hold the values. Have a read of stack.doc +and have a look at the relevant header files to see what I mean. If there +is an error while malloc()ing the structure, NULL is returned. + +The 'free' function will free() all the sub components of a particular +structure. If any of those sub components have been 'removed', replace +them with NULL pointers, the 'free' functions are tolerant of NULL fields. + +The 'd2i' function copies a binary representation into a C structure. It +operates as follows. 'a' is a pointer to a pointer to +the structure to populate, 'pp' is a pointer to a pointer to where the DER +byte string is located and 'length' is the length of the '*pp' data. +If there are no errors, a pointer to the populated structure is returned. +If there is an error, NULL is returned. Errors can occur because of +malloc() failures but normally they will be due to syntax errors in the DER +encoded data being parsed. It is also an error if there was an +attempt to read more that 'length' bytes from '*p'. If +everything works correctly, the value in '*p' is updated +to point at the location just beyond where the DER +structure was read from. In this way, chained calls to 'd2i' type +functions can be made, with the pointer into the 'data' array being +'walked' along the input byte array. +Depending on the value passed for 'a', different things will be done. If +'a' is NULL, a new structure will be malloc()ed and returned. If '*a' is +NULL, a new structure will be malloc()ed and put into '*a' and returned. +If '*a' is not NULL, the structure in '*a' will be populated, or in the +case of an error, free()ed and then returned. +Having these semantics means that a structure +can call a 'd2i' function to populate a field and if the field is currently +NULL, the structure will be created. + +The 'i2d' function type is used to copy a C structure to a byte array. +The parameter 'a' is the structure to convert and '*p' is where to put it. +As for the 'd2i' type structure, 'p' is updated to point after the last +byte written. If p is NULL, no data is written. The function also returns +the number of bytes written. Where this becomes useful is that if the +function is called with a NULL 'p' value, the length is returned. This can +then be used to malloc() an array of bytes and then the same function can +be recalled passing the malloced array to be written to. e.g. + +int len; +unsigned char *bytes,*p; +len=i2d_X509(x,NULL); /* get the size of the ASN1 encoding of 'x' */ +if ((bytes=(unsigned char *)malloc(len)) == NULL) + goto err; +p=bytes; +i2d_X509(x,&p); + +Please note that a new variable, 'p' was passed to i2d_X509. After the +call to i2d_X509 p has been incremented by len bytes. + +Now the reason for this functional organisation is that it allows nested +structures to be built up by calling these functions as required. There +are various macros used to help write the general 'i2d', 'd2i', 'new' and +'free' functions. They are discussed in another file and would only be +used by some-one wanting to add new structures to the library. As you +might be able to guess, the process of writing ASN.1 files can be a bit CPU +expensive for complex structures. I'm willing to live with this since the +simpler library code make my life easier and hopefully most programs using +these routines will have their execution profiles dominated by cipher or +message digest routines. +What follows is a list of 'TYPE' values and the corresponding ASN.1 +structure and where it is used. + +TYPE ASN.1 +ASN1_INTEGER INTEGER +ASN1_BIT_STRING BIT STRING +ASN1_OCTET_STRING OCTET STRING +ASN1_OBJECT OBJECT IDENTIFIER +ASN1_PRINTABLESTRING PrintableString +ASN1_T61STRING T61String +ASN1_IA5STRING IA5String +ASN1_UTCTIME UTCTime +ASN1_TYPE Any of the above mentioned types plus SEQUENCE and SET + +Most of the above mentioned types are actualled stored in the +ASN1_BIT_STRING type and macros are used to differentiate between them. +The 3 types used are + +typedef struct asn1_object_st + { + /* both null if a dynamic ASN1_OBJECT, one is + * defined if a 'static' ASN1_OBJECT */ + char *sn,*ln; + int nid; + int length; + unsigned char *data; + } ASN1_OBJECT; +This is used to store ASN1 OBJECTS. Read 'objects.doc' for details ono +routines to manipulate this structure. 'sn' and 'ln' are used to hold text +strings that represent the object (short name and long or lower case name). +These are used by the 'OBJ' library. 'nid' is a number used by the OBJ +library to uniquely identify objects. The ASN1 routines will populate the +'length' and 'data' fields which will contain the bit string representing +the object. + +typedef struct asn1_bit_string_st + { + int length; + int type; + unsigned char *data; + } ASN1_BIT_STRING; +This structure is used to hold all the other base ASN1 types except for +ASN1_UTCTIME (which is really just a 'char *'). Length is the number of +bytes held in data and type is the ASN1 type of the object (there is a list +in asn1.h). + +typedef struct asn1_type_st + { + int type; + union { + char *ptr; + ASN1_INTEGER * integer; + ASN1_BIT_STRING * bit_string; + ASN1_OCTET_STRING * octet_string; + ASN1_OBJECT * object; + ASN1_PRINTABLESTRING * printablestring; + ASN1_T61STRING * t61string; + ASN1_IA5STRING * ia5string; + ASN1_UTCTIME * utctime; + ASN1_BIT_STRING * set; + ASN1_BIT_STRING * sequence; + } value; + } ASN1_TYPE; +This structure is used in a few places when 'any' type of object can be +expected. + +X509 Certificate +X509_CINF CertificateInfo +X509_ALGOR AlgorithmIdentifier +X509_NAME Name +X509_NAME_ENTRY A single sub component of the name. +X509_VAL Validity +X509_PUBKEY SubjectPublicKeyInfo +The above mentioned types are declared in x509.h. They are all quite +straight forward except for the X509_NAME/X509_NAME_ENTRY pair. +A X509_NAME is a STACK (see stack.doc) of X509_NAME_ENTRY's. +typedef struct X509_name_entry_st + { + ASN1_OBJECT *object; + ASN1_BIT_STRING *value; + int set; + int size; /* temp variable */ + } X509_NAME_ENTRY; +The size is a temporary variable used by i2d_NAME and set is the set number +for the particular NAME_ENTRY. A X509_NAME is encoded as a sequence of +sequence of sets. Normally each set contains only a single item. +Sometimes it contains more. Normally throughout this library there will be +only one item per set. The set field contains the 'set' that this entry is +a member of. So if you have just created a X509_NAME structure and +populated it with X509_NAME_ENTRYs, you should then traverse the X509_NAME +(which is just a STACK) and set the 'set/' field to incrementing numbers. +For more details on why this is done, read the ASN.1 spec for Distinguished +Names. + +X509_REQ CertificateRequest +X509_REQ_INFO CertificateRequestInfo +These are used to hold certificate requests. + +X509_CRL CertificateRevocationList +These are used to hold a certificate revocation list + +RSAPrivateKey PrivateKeyInfo +RSAPublicKey PublicKeyInfo +Both these 'function groups' operate on 'RSA' structures (see rsa.doc). +The difference is that the RSAPublicKey operations only manipulate the m +and e fields in the RSA structure. + +DSAPrivateKey DSS private key +DSAPublicKey DSS public key +Both these 'function groups' operate on 'DSS' structures (see dsa.doc). +The difference is that the RSAPublicKey operations only manipulate the +XXX fields in the DSA structure. + +DHparams DHParameter +This is used to hold the p and g value for The Diffie-Hellman operation. +The function deal with the 'DH' strucure (see dh.doc). + +Now all of these function types can be used with several other functions to give +quite useful set of general manipulation routines. Normally one would +not uses these functions directly but use them via macros. + +char *ASN1_dup(int (*i2d)(),char *(*d2i)(),char *x); +'x' is the input structure case to a 'char *', 'i2d' is the 'i2d_TYPE' +function for the type that 'x' is and d2i is the 'd2i_TYPE' function for the +type that 'x' is. As is obvious from the parameters, this function +duplicates the strucutre by transforming it into the DER form and then +re-loading it into a new strucutre and returning the new strucutre. This +is obviously a bit cpu intensive but when faced with a complex dynamic +structure this is the simplest programming approach. There are macros for +duplicating the major data types but is simple to add extras. + +char *ASN1_d2i_fp(char *(*new)(),char *(*d2i)(),FILE *fp,unsigned char **x); +'x' is a pointer to a pointer of the 'desired type'. new and d2i are the +corresponding 'TYPE_new' and 'd2i_TYPE' functions for the type and 'fp' is +an open file pointer to read from. This function reads from 'fp' as much +data as it can and then uses 'd2i' to parse the bytes to load and return +the parsed strucutre in 'x' (if it was non-NULL) and to actually return the +strucutre. The behavior of 'x' is as per all the other d2i functions. + +char *ASN1_d2i_bio(char *(*new)(),char *(*d2i)(),BIO *fp,unsigned char **x); +The 'BIO' is the new IO type being used in SSLeay (see bio.doc). This +function is the same as ASN1_d2i_fp() except for the BIO argument. +ASN1_d2i_fp() actually calls this function. + +int ASN1_i2d_fp(int (*i2d)(),FILE *out,unsigned char *x); +'x' is converted to bytes by 'i2d' and then written to 'out'. ASN1_i2d_fp +and ASN1_d2i_fp are not really symetric since ASN1_i2d_fp will read all +available data from the file pointer before parsing a single item while +ASN1_i2d_fp can be used to write a sequence of data objects. To read a +series of objects from a file I would sugest loading the file into a buffer +and calling the relevent 'd2i' functions. + +char *ASN1_d2i_bio(char *(*new)(),char *(*d2i)(),BIO *fp,unsigned char **x); +This function is the same as ASN1_i2d_fp() except for the BIO argument. +ASN1_i2d_fp() actually calls this function. + +char * PEM_ASN1_read(char *(*d2i)(),char *name,FILE *fp,char **x,int (*cb)()); +This function will read the next PEM encoded (base64) object of the same +type as 'x' (loaded by the d2i function). 'name' is the name that is in +the '-----BEGIN name-----' that designates the start of that object type. +If the data is encrypted, 'cb' will be called to prompt for a password. If +it is NULL a default function will be used to prompt from the password. +'x' is delt with as per the standard 'd2i' function interface. This +function can be used to read a series of objects from a file. While any +data type can be encrypted (see PEM_ASN1_write) only RSA private keys tend +to be encrypted. + +char * PEM_ASN1_read_bio(char *(*d2i)(),char *name,BIO *fp, + char **x,int (*cb)()); +Same as PEM_ASN1_read() except using a BIO. This is called by +PEM_ASN1_read(). + +int PEM_ASN1_write(int (*i2d)(),char *name,FILE *fp,char *x,EVP_CIPHER *enc, + unsigned char *kstr,int klen,int (*callback)()); + +int PEM_ASN1_write_bio(int (*i2d)(),char *name,BIO *fp, + char *x,EVP_CIPHER *enc,unsigned char *kstr,int klen, + int (*callback)()); + +int ASN1_sign(int (*i2d)(), X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, char *data, RSA *rsa, EVP_MD *type); +int ASN1_verify(int (*i2d)(), X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,char *data, RSA *rsa); + +int ASN1_BIT_STRING_cmp(ASN1_BIT_STRING *a, ASN1_BIT_STRING *b); +ASN1_BIT_STRING *ASN1_BIT_STRING_type_new(int type ); + +int ASN1_UTCTIME_check(ASN1_UTCTIME *a); +void ASN1_UTCTIME_print(BIO *fp,ASN1_UTCTIME *a); +ASN1_UTCTIME *ASN1_UTCTIME_dup(ASN1_UTCTIME *a); + +ASN1_BIT_STRING *d2i_asn1_print_type(ASN1_BIT_STRING **a,unsigned char **pp, + long length,int type); + +int i2d_ASN1_SET(STACK *a, unsigned char **pp, + int (*func)(), int ex_tag, int ex_class); +STACK * d2i_ASN1_SET(STACK **a, unsigned char **pp, long length, + char *(*func)(), int ex_tag, int ex_class); + +int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *object); +int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); +int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); + +int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +long ASN1_INTEGER_get(ASN1_INTEGER *a); +ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *bn, ASN1_INTEGER *ai); +BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *ai,BIGNUM *bn); + +/* given a string, return the correct type. Max is the maximum number + * of bytes to parse. It stops parsing when 'max' bytes have been + * processed or a '\0' is hit */ +int ASN1_PRINTABLE_type(unsigned char *s,int max); + +void ASN1_parse(BIO *fp,unsigned char *pp,long len); + +int i2d_ASN1_bytes(ASN1_BIT_STRING *a, unsigned char **pp, int tag, int class); +ASN1_BIT_STRING *d2i_ASN1_bytes(ASN1_OCTET_STRING **a, unsigned char **pp, + long length, int Ptag, int Pclass); + +/* PARSING */ +int asn1_Finish(ASN1_CTX *c); + +/* SPECIALS */ +int ASN1_get_object(unsigned char **pp, long *plength, int *ptag, + int *pclass, long omax); +int ASN1_check_infinite_end(unsigned char **p,long len); +void ASN1_put_object(unsigned char **pp, int constructed, int length, + int tag, int class); +int ASN1_object_size(int constructed, int length, int tag); + +X509 * X509_get_cert(CERTIFICATE_CTX *ctx,X509_NAME * name,X509 *tmp_x509); +int X509_add_cert(CERTIFICATE_CTX *ctx,X509 *); + +char * X509_cert_verify_error_string(int n); +int X509_add_cert_file(CERTIFICATE_CTX *c,char *file, int type); +char * X509_gmtime (char *s, long adj); +int X509_add_cert_dir (CERTIFICATE_CTX *c,char *dir, int type); +int X509_load_verify_locations (CERTIFICATE_CTX *ctx, + char *file_env, char *dir_env); +int X509_set_default_verify_paths(CERTIFICATE_CTX *cts); +X509 * X509_new_D2i_X509(int len, unsigned char *p); +char * X509_get_default_cert_area(void ); +char * X509_get_default_cert_dir(void ); +char * X509_get_default_cert_file(void ); +char * X509_get_default_cert_dir_env(void ); +char * X509_get_default_cert_file_env(void ); +char * X509_get_default_private_dir(void ); +X509_REQ *X509_X509_TO_req(X509 *x, RSA *rsa); +int X509_cert_verify(CERTIFICATE_CTX *ctx,X509 *xs, int (*cb)()); + +CERTIFICATE_CTX *CERTIFICATE_CTX_new(); +void CERTIFICATE_CTX_free(CERTIFICATE_CTX *c); + +void X509_NAME_print(BIO *fp, X509_NAME *name, int obase); +int X509_print_fp(FILE *fp,X509 *x); +int X509_print(BIO *fp,X509 *x); + +X509_INFO * X509_INFO_new(void); +void X509_INFO_free(X509_INFO *a); + +char * X509_NAME_oneline(X509_NAME *a); + +#define X509_verify(x,rsa) +#define X509_REQ_verify(x,rsa) +#define X509_CRL_verify(x,rsa) + +#define X509_sign(x,rsa,md) +#define X509_REQ_sign(x,rsa,md) +#define X509_CRL_sign(x,rsa,md) + +#define X509_dup(x509) +#define d2i_X509_fp(fp,x509) +#define i2d_X509_fp(fp,x509) +#define d2i_X509_bio(bp,x509) +#define i2d_X509_bio(bp,x509) + +#define X509_CRL_dup(crl) +#define d2i_X509_CRL_fp(fp,crl) +#define i2d_X509_CRL_fp(fp,crl) +#define d2i_X509_CRL_bio(bp,crl) +#define i2d_X509_CRL_bio(bp,crl) + +#define X509_REQ_dup(req) +#define d2i_X509_REQ_fp(fp,req) +#define i2d_X509_REQ_fp(fp,req) +#define d2i_X509_REQ_bio(bp,req) +#define i2d_X509_REQ_bio(bp,req) + +#define RSAPrivateKey_dup(rsa) +#define d2i_RSAPrivateKey_fp(fp,rsa) +#define i2d_RSAPrivateKey_fp(fp,rsa) +#define d2i_RSAPrivateKey_bio(bp,rsa) +#define i2d_RSAPrivateKey_bio(bp,rsa) + +#define X509_NAME_dup(xn) +#define X509_NAME_ENTRY_dup(ne) + +void X509_REQ_print_fp(FILE *fp,X509_REQ *req); +void X509_REQ_print(BIO *fp,X509_REQ *req); + +RSA *X509_REQ_extract_key(X509_REQ *req); +RSA *X509_extract_key(X509 *x509); + +int X509_issuer_and_serial_cmp(X509 *a, X509 *b); +unsigned long X509_issuer_and_serial_hash(X509 *a); + +X509_NAME * X509_get_issuer_name(X509 *a); +int X509_issuer_name_cmp(X509 *a, X509 *b); +unsigned long X509_issuer_name_hash(X509 *a); + +X509_NAME * X509_get_subject_name(X509 *a); +int X509_subject_name_cmp(X509 *a,X509 *b); +unsigned long X509_subject_name_hash(X509 *x); + +int X509_NAME_cmp (X509_NAME *a, X509_NAME *b); +unsigned long X509_NAME_hash(X509_NAME *x); + diff --git a/doc/bio.doc b/doc/bio.doc new file mode 100644 index 0000000000..545a57cdff --- /dev/null +++ b/doc/bio.doc @@ -0,0 +1,423 @@ +BIO Routines + +This documentation is rather sparse, you are probably best +off looking at the code for specific details. + +The BIO library is a IO abstraction that was originally +inspired by the need to have callbacks to perform IO to FILE +pointers when using Windows 3.1 DLLs. There are two types +of BIO; a source/sink type and a filter type. +The source/sink methods are as follows: +- BIO_s_mem() memory buffer - a read/write byte array that + grows until memory runs out :-). +- BIO_s_file() FILE pointer - A wrapper around the normal + 'FILE *' commands, good for use with stdin/stdout. +- BIO_s_fd() File descriptor - A wrapper around file + descriptors, often used with pipes. +- BIO_s_socket() Socket - Used around sockets. It is + mostly in the Microsoft world that sockets are different + from file descriptors and there are all those ugly winsock + commands. +- BIO_s_null() Null - read nothing and write nothing.; a + useful endpoint for filter type BIO's specifically things + like the message digest BIO. + +The filter types are +- BIO_f_buffer() IO buffering - does output buffering into + larger chunks and performs input buffering to allow gets() + type functions. +- BIO_f_md() Message digest - a transparent filter that can + be asked to return a message digest for the data that has + passed through it. +- BIO_f_cipher() Encrypt or decrypt all data passing + through the filter. +- BIO_f_base64() Base64 decode on read and encode on write. +- BIO_f_ssl() A filter that performs SSL encryption on the + data sent through it. + +Base BIO functions. +The BIO library has a set of base functions that are +implemented for each particular type. Filter BIOs will +normally call the equivalent function on the source/sink BIO +that they are layered on top of after they have performed +some modification to the data stream. Multiple filter BIOs +can be 'push' into a stack of modifers, so to read from a +file, unbase64 it, then decrypt it, a BIO_f_cipher, +BIO_f_base64 and a BIO_s_file would probably be used. If a +sha-1 and md5 message digest needed to be generated, a stack +two BIO_f_md() BIOs and a BIO_s_null() BIO could be used. +The base functions are +- BIO *BIO_new(BIO_METHOD *type); Create a new BIO of type 'type'. +- int BIO_free(BIO *a); Free a BIO structure. Depending on + the configuration, this will free the underlying data + object for a source/sink BIO. +- int BIO_read(BIO *b, char *data, int len); Read upto 'len' + bytes into 'data'. +- int BIO_gets(BIO *bp,char *buf, int size); Depending on + the BIO, this can either be a 'get special' or a get one + line of data, as per fgets(); +- int BIO_write(BIO *b, char *data, int len); Write 'len' + bytes from 'data' to the 'b' BIO. +- int BIO_puts(BIO *bp,char *buf); Either a 'put special' or + a write null terminated string as per fputs(). +- long BIO_ctrl(BIO *bp,int cmd,long larg,char *parg); A + control function which is used to manipulate the BIO + structure and modify it's state and or report on it. This + function is just about never used directly, rather it + should be used in conjunction with BIO_METHOD specific + macros. +- BIO *BIO_push(BIO *new_top, BIO *old); new_top is apped to the + top of the 'old' BIO list. new_top should be a filter BIO. + All writes will go through 'new_top' first and last on read. + 'old' is returned. +- BIO *BIO_pop(BIO *bio); the new topmost BIO is returned, NULL if + there are no more. + +If a particular low level BIO method is not supported +(normally BIO_gets()), -2 will be returned if that method is +called. Otherwise the IO methods (read, write, gets, puts) +will return the number of bytes read or written, and 0 or -1 +for error (or end of input). For the -1 case, +BIO_should_retry(bio) can be called to determine if it was a +genuine error or a temporary problem. -2 will also be +returned if the BIO has not been initalised yet, in all +cases, the correct error codes are set (accessible via the +ERR library). + + +The following functions are convenience functions: +- int BIO_printf(BIO *bio, char * format, ..); printf but + to a BIO handle. +- long BIO_ctrl_int(BIO *bp,int cmd,long larg,int iarg); a + convenience function to allow a different argument types + to be passed to BIO_ctrl(). +- int BIO_dump(BIO *b,char *bytes,int len); output 'len' + bytes from 'bytes' in a hex dump debug format. +- long BIO_debug_callback(BIO *bio, int cmd, char *argp, int + argi, long argl, long ret) - a default debug BIO callback, + this is mentioned below. To use this one normally has to + use the BIO_set_callback_arg() function to assign an + output BIO for the callback to use. +- BIO *BIO_find_type(BIO *bio,int type); when there is a 'stack' + of BIOs, this function scan the list and returns the first + that is of type 'type', as listed in buffer.h under BIO_TYPE_XXX. +- void BIO_free_all(BIO *bio); Free the bio and all other BIOs + in the list. It walks the bio->next_bio list. + + + +Extra commands are normally implemented as macros calling BIO_ctrl(). +- BIO_number_read(BIO *bio) - the number of bytes processed + by BIO_read(bio,.). +- BIO_number_written(BIO *bio) - the number of bytes written + by BIO_write(bio,.). +- BIO_reset(BIO *bio) - 'reset' the BIO. +- BIO_eof(BIO *bio) - non zero if we are at the current end + of input. +- BIO_set_close(BIO *bio, int close_flag) - set the close flag. +- BIO_get_close(BIO *bio) - return the close flag. + BIO_pending(BIO *bio) - return the number of bytes waiting + to be read (normally buffered internally). +- BIO_flush(BIO *bio) - output any data waiting to be output. +- BIO_should_retry(BIO *io) - after a BIO_read/BIO_write + operation returns 0 or -1, a call to this function will + return non zero if you should retry the call later (this + is for non-blocking IO). +- BIO_should_read(BIO *io) - we should retry when data can + be read. +- BIO_should_write(BIO *io) - we should retry when data can + be written. +- BIO_method_name(BIO *io) - return a string for the method name. +- BIO_method_type(BIO *io) - return the unique ID of the BIO method. +- BIO_set_callback(BIO *io, long (*callback)(BIO *io, int + cmd, char *argp, int argi, long argl, long ret); - sets + the debug callback. +- BIO_get_callback(BIO *io) - return the assigned function + as mentioned above. +- BIO_set_callback_arg(BIO *io, char *arg) - assign some + data against the BIO. This is normally used by the debug + callback but could in reality be used for anything. To + get an idea of how all this works, have a look at the code + in the default debug callback mentioned above. The + callback can modify the return values. + +Details of the BIO_METHOD structure. +typedef struct bio_method_st + { + int type; + char *name; + int (*bwrite)(); + int (*bread)(); + int (*bputs)(); + int (*bgets)(); + long (*ctrl)(); + int (*create)(); + int (*destroy)(); + } BIO_METHOD; + +The 'type' is the numeric type of the BIO, these are listed in buffer.h; +'Name' is a textual representation of the BIO 'type'. +The 7 function pointers point to the respective function +methods, some of which can be NULL if not implemented. +The BIO structure +typedef struct bio_st + { + BIO_METHOD *method; + long (*callback)(BIO * bio, int mode, char *argp, int + argi, long argl, long ret); + char *cb_arg; /* first argument for the callback */ + int init; + int shutdown; + int flags; /* extra storage */ + int num; + char *ptr; + struct bio_st *next_bio; /* used by filter BIOs */ + int references; + unsigned long num_read; + unsigned long num_write; + } BIO; + +- 'Method' is the BIO method. +- 'callback', when configured, is called before and after + each BIO method is called for that particular BIO. This + is intended primarily for debugging and of informational feedback. +- 'init' is 0 when the BIO can be used for operation. + Often, after a BIO is created, a number of operations may + need to be performed before it is available for use. An + example is for BIO_s_sock(). A socket needs to be + assigned to the BIO before it can be used. +- 'shutdown', this flag indicates if the underlying + comunication primative being used should be closed/freed + when the BIO is closed. +- 'flags' is used to hold extra state. It is primarily used + to hold information about why a non-blocking operation + failed and to record startup protocol information for the + SSL BIO. +- 'num' and 'ptr' are used to hold instance specific state + like file descriptors or local data structures. +- 'next_bio' is used by filter BIOs to hold the pointer of the + next BIO in the chain. written data is sent to this BIO and + data read is taken from it. +- 'references' is used to indicate the number of pointers to + this structure. This needs to be '1' before a call to + BIO_free() is made if the BIO_free() function is to + actually free() the structure, otherwise the reference + count is just decreased. The actual BIO subsystem does + not really use this functionality but it is useful when + used in more advanced applicaion. +- num_read and num_write are the total number of bytes + read/written via the 'read()' and 'write()' methods. + +BIO_ctrl operations. +The following is the list of standard commands passed as the +second parameter to BIO_ctrl() and should be supported by +all BIO as best as possible. Some are optional, some are +manditory, in any case, where is makes sense, a filter BIO +should pass such requests to underlying BIO's. +- BIO_CTRL_RESET - Reset the BIO back to an initial state. +- BIO_CTRL_EOF - return 0 if we are not at the end of input, + non 0 if we are. +- BIO_CTRL_INFO - BIO specific special command, normal + information return. +- BIO_CTRL_SET - set IO specific parameter. +- BIO_CTRL_GET - get IO specific parameter. +- BIO_CTRL_GET_CLOSE - Get the close on BIO_free() flag, one + of BIO_CLOSE or BIO_NOCLOSE. +- BIO_CTRL_SET_CLOSE - Set the close on BIO_free() flag. +- BIO_CTRL_PENDING - Return the number of bytes available + for instant reading +- BIO_CTRL_FLUSH - Output pending data, return number of bytes output. +- BIO_CTRL_SHOULD_RETRY - After an IO error (-1 returned) + should we 'retry' when IO is possible on the underlying IO object. +- BIO_CTRL_RETRY_TYPE - What kind of IO are we waiting on. + +The following command is a special BIO_s_file() specific option. +- BIO_CTRL_SET_FILENAME - specify a file to open for IO. + +The BIO_CTRL_RETRY_TYPE needs a little more explanation. +When performing non-blocking IO, or say reading on a memory +BIO, when no data is present (or cannot be written), +BIO_read() and/or BIO_write() will return -1. +BIO_should_retry(bio) will return true if this is due to an +IO condition rather than an actual error. In the case of +BIO_s_mem(), a read when there is no data will return -1 and +a should retry when there is more 'read' data. +The retry type is deduced from 2 macros +BIO_should_read(bio) and BIO_should_write(bio). +Now while it may appear obvious that a BIO_read() failure +should indicate that a retry should be performed when more +read data is available, this is often not true when using +things like an SSL BIO. During the SSL protocol startup +multiple reads and writes are performed, triggered by any +SSL_read or SSL_write. +So to write code that will transparently handle either a +socket or SSL BIO, + i=BIO_read(bio,..) + if (I == -1) + { + if (BIO_should_retry(bio)) + { + if (BIO_should_read(bio)) + { + /* call us again when BIO can be read */ + } + if (BIO_should_write(bio)) + { + /* call us again when BIO can be written */ + } + } + } + +At this point in time only read and write conditions can be +used but in the future I can see the situation for other +conditions, specifically with SSL there could be a condition +of a X509 certificate lookup taking place and so the non- +blocking BIO_read would require a retry when the certificate +lookup subsystem has finished it's lookup. This is all +makes more sense and is easy to use in a event loop type +setup. +When using the SSL BIO, either SSL_read() or SSL_write()s +can be called during the protocol startup and things will +still work correctly. +The nice aspect of the use of the BIO_should_retry() macro +is that all the errno codes that indicate a non-fatal error +are encapsulated in one place. The Windows specific error +codes and WSAGetLastError() calls are also hidden from the +application. + +Notes on each BIO method. +Normally buffer.h is just required but depending on the +BIO_METHOD, ssl.h or evp.h will also be required. + +BIO_METHOD *BIO_s_mem(void); +- BIO_set_mem_buf(BIO *bio, BUF_MEM *bm, int close_flag) - + set the underlying BUF_MEM structure for the BIO to use. +- BIO_get_mem_ptr(BIO *bio, char **pp) - if pp is not NULL, + set it to point to the memory array and return the number + of bytes available. +A read/write BIO. Any data written is appended to the +memory array and any read is read from the front. This BIO +can be used for read/write at the same time. BIO_gets() is +supported in the fgets() sense. +BIO_CTRL_INFO can be used to retrieve pointers to the memory +buffer and it's length. + +BIO_METHOD *BIO_s_file(void); +- BIO_set_fp(BIO *bio, FILE *fp, int close_flag) - set 'FILE *' to use. +- BIO_get_fp(BIO *bio, FILE **fp) - get the 'FILE *' in use. +- BIO_read_filename(BIO *bio, char *name) - read from file. +- BIO_write_filename(BIO *bio, char *name) - write to file. +- BIO_append_filename(BIO *bio, char *name) - append to file. +This BIO sits over the normal system fread()/fgets() type +functions. Gets() is supported. This BIO in theory could be +used for read and write but it is best to think of each BIO +of this type as either a read or a write BIO, not both. + +BIO_METHOD *BIO_s_socket(void); +BIO_METHOD *BIO_s_fd(void); +- BIO_sock_should_retry(int i) - the underlying function + used to determine if a call should be retried; the + argument is the '0' or '-1' returned by the previous BIO + operation. +- BIO_fd_should_retry(int i) - same as the +- BIO_sock_should_retry() except that it is different internally. +- BIO_set_fd(BIO *bio, int fd, int close_flag) - set the + file descriptor to use +- BIO_get_fd(BIO *bio, int *fd) - get the file descriptor. +These two methods are very similar. Gets() is not +supported, if you want this functionality, put a +BIO_f_buffer() onto it. This BIO is bi-directional if the +underlying file descriptor is. This is normally the case +for sockets but not the case for stdio descriptors. + +BIO_METHOD *BIO_s_null(void); +Read and write as much data as you like, it all disappears +into this BIO. + +BIO_METHOD *BIO_f_buffer(void); +- BIO_get_buffer_num_lines(BIO *bio) - return the number of + complete lines in the buffer. +- BIO_set_buffer_size(BIO *bio, long size) - set the size of + the buffers. +This type performs input and output buffering. It performs +both at the same time. The size of the buffer can be set +via the set buffer size option. Data buffered for output is +only written when the buffer fills. + +BIO_METHOD *BIO_f_ssl(void); +- BIO_set_ssl(BIO *bio, SSL *ssl, int close_flag) - the SSL + structure to use. +- BIO_get_ssl(BIO *bio, SSL **ssl) - get the SSL structure + in use. +The SSL bio is a little different from normal BIOs because +the underlying SSL structure is a little different. A SSL +structure performs IO via a read and write BIO. These can +be different and are normally set via the +SSL_set_rbio()/SSL_set_wbio() calls. The SSL_set_fd() calls +are just wrappers that create socket BIOs and then call +SSL_set_bio() where the read and write BIOs are the same. +The BIO_push() operation makes the SSLs IO BIOs the same, so +make sure the BIO pushed is capable of two directional +traffic. If it is not, you will have to install the BIOs +via the more conventional SSL_set_bio() call. BIO_pop() will retrieve +the 'SSL read' BIO. + +BIO_METHOD *BIO_f_md(void); +- BIO_set_md(BIO *bio, EVP_MD *md) - set the message digest + to use. +- BIO_get_md(BIO *bio, EVP_MD **mdp) - return the digest + method in use in mdp, return 0 if not set yet. +- BIO_reset() reinitializes the digest (EVP_DigestInit()) + and passes the reset to the underlying BIOs. +All data read or written via BIO_read() or BIO_write() to +this BIO will be added to the calculated digest. This +implies that this BIO is only one directional. If read and +write operations are performed, two separate BIO_f_md() BIOs +are reuqired to generate digests on both the input and the +output. BIO_gets(BIO *bio, char *md, int size) will place the +generated digest into 'md' and return the number of bytes. +The EVP_MAX_MD_SIZE should probably be used to size the 'md' +array. Reading the digest will also reset it. + +BIO_METHOD *BIO_f_cipher(void); +- BIO_reset() reinitializes the cipher. +- BIO_flush() should be called when the last bytes have been + output to flush the final block of block ciphers. +- BIO_get_cipher_status(BIO *b), when called after the last + read from a cipher BIO, returns non-zero if the data + decrypted correctly, otherwise, 0. +- BIO_set_cipher(BIO *b, EVP_CIPHER *c, unsigned char *key, + unsigned char *iv, int encrypt) This function is used to + setup a cipher BIO. The length of key and iv are + specified by the choice of EVP_CIPHER. Encrypt is 1 to + encrypt and 0 to decrypt. + +BIO_METHOD *BIO_f_base64(void); +- BIO_flush() should be called when the last bytes have been output. +This BIO base64 encodes when writing and base64 decodes when +reading. It will scan the input until a suitable begin line +is found. After reading data, BIO_reset() will reset the +BIO to start scanning again. Do not mix reading and writing +on the same base64 BIO. It is meant as a single stream BIO. + +Directions type +both BIO_s_mem() +one/both BIO_s_file() +both BIO_s_fd() +both BIO_s_socket() +both BIO_s_null() +both BIO_f_buffer() +one BIO_f_md() +one BIO_f_cipher() +one BIO_f_base64() +both BIO_f_ssl() + +It is easy to mix one and two directional BIOs, all one has +to do is to keep two separate BIO pointers for reading and +writing and be careful about usage of underlying BIOs. The +SSL bio by it's very nature has to be two directional but +the BIO_push() command will push the one BIO into the SSL +BIO for both reading and writing. + +The best example program to look at is apps/enc.c and/or perhaps apps/dgst.c. + diff --git a/doc/blowfish.doc b/doc/blowfish.doc new file mode 100644 index 0000000000..3a7291f371 --- /dev/null +++ b/doc/blowfish.doc @@ -0,0 +1,149 @@ +The Blowfish library. + +Blowfish is a block cipher that operates on 64bit (8 byte) quantities. It +uses variable size key, but 128bit (16 byte) key would normally be considered +good. It can be used in all the modes that DES can be used. This +library implements the ecb, cbc, cfb64, ofb64 modes. + +Blowfish is quite a bit faster that DES, and much faster than IDEA or +RC2. It is one of the faster block ciphers. + +For all calls that have an 'input' and 'output' variables, they can be the +same. + +This library requires the inclusion of 'blowfish.h'. + +All of the encryption functions take what is called an BF_KEY as an +argument. An BF_KEY is an expanded form of the Blowfish key. +For all modes of the Blowfish algorithm, the BF_KEY used for +decryption is the same one that was used for encryption. + +The define BF_ENCRYPT is passed to specify encryption for the functions +that require an encryption/decryption flag. BF_DECRYPT is passed to +specify decryption. + +Please note that any of the encryption modes specified in my DES library +could be used with Blowfish. I have only implemented ecb, cbc, cfb64 and +ofb64 for the following reasons. +- ecb is the basic Blowfish encryption. +- cbc is the normal 'chaining' form for block ciphers. +- cfb64 can be used to encrypt single characters, therefore input and output + do not need to be a multiple of 8. +- ofb64 is similar to cfb64 but is more like a stream cipher, not as + secure (not cipher feedback) but it does not have an encrypt/decrypt mode. +- If you want triple Blowfish, thats 384 bits of key and you must be totally + obsessed with security. Still, if you want it, it is simple enough to + copy the function from the DES library and change the des_encrypt to + BF_encrypt; an exercise left for the paranoid reader :-). + +The functions are as follows: + +void BF_set_key( +BF_KEY *ks; +int len; +unsigned char *key; + BF_set_key converts an 'len' byte key into a BF_KEY. + A 'ks' is an expanded form of the 'key' which is used to + perform actual encryption. It can be regenerated from the Blowfish key + so it only needs to be kept when encryption or decryption is about + to occur. Don't save or pass around BF_KEY's since they + are CPU architecture dependent, 'key's are not. Blowfish is an + interesting cipher in that it can be used with a variable length + key. 'len' is the length of 'key' to be used as the key. + A 'len' of 16 is recomended by me, but blowfish can use upto + 72 bytes. As a warning, blowfish has a very very slow set_key + function, it actually runs BF_encrypt 521 times. + +void BF_encrypt( +unsigned long *data, +BF_KEY *key, +int encrypt); + This is the Blowfish encryption function that gets called by just about + every other Blowfish routine in the library. You should not use this + function except to implement 'modes' of Blowfish. + I say this because the + functions that call this routine do the conversion from 'char *' to + long, and this needs to be done to make sure 'non-aligned' memory + access do not occur. + Data is a pointer to 2 unsigned long's and key is the + BF_KEY to use. Encryption or decryption is indicated by 'encrypt'. + which can have the values BF_ENCRYPT or BF_DECRYPT. + +void BF_ecb_encrypt( +unsigned char *in, +unsigned char *out, +BF_KEY *key, +int encrypt); + This is the basic Electronic Code Book form of Blowfish (in DES this + mode is called Electronic Code Book so I'm going to use the term + for blowfish as well. + Input is encrypted into output using the key represented by + key. Depending on the encrypt, encryption or + decryption occurs. Input is 8 bytes long and output is 8 bytes. + +void BF_cbc_encrypt( +unsigned char *in, +unsigned char *out, +long length, +BF_KEY *ks, +unsigned char *ivec, +int encrypt); + This routine implements Blowfish in Cipher Block Chaining mode. + Input, which should be a multiple of 8 bytes is encrypted + (or decrypted) to output which will also be a multiple of 8 bytes. + The number of bytes is in length (and from what I've said above, + should be a multiple of 8). If length is not a multiple of 8, bad + things will probably happen. ivec is the initialisation vector. + This function updates iv after each call so that it can be passed to + the next call to BF_cbc_encrypt(). + +void BF_cfb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +BF_KEY *schedule, +unsigned char *ivec, +int *num, +int encrypt); + This is one of the more useful functions in this Blowfish library, it + implements CFB mode of Blowfish with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + 'Encrypt' is used to indicate encryption or decryption. + CFB64 mode operates by using the cipher to generate a stream + of bytes which is used to encrypt the plain text. + The cipher text is then encrypted to generate the next 64 bits to + be xored (incrementally) with the next 64 bits of plain + text. As can be seen from this, to encrypt or decrypt, + the same 'cipher stream' needs to be generated but the way the next + block of data is gathered for encryption is different for + encryption and decryption. + +void BF_ofb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +BF_KEY *schedule, +unsigned char *ivec, +int *num); + This functions implements OFB mode of Blowfish with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + This is in effect a stream cipher, there is no encryption or + decryption mode. + +For reading passwords, I suggest using des_read_pw_string() from my DES library. +To generate a password from a text string, I suggest using MD5 (or MD2) to +produce a 16 byte message digest that can then be passed directly to +BF_set_key(). + +===== +For more information about the specific Blowfish modes in this library +(ecb, cbc, cfb and ofb), read the section entitled 'Modes of DES' from the +documentation on my DES library. What is said about DES is directly +applicable for Blowfish. + diff --git a/doc/bn.doc b/doc/bn.doc new file mode 100644 index 0000000000..2358c20f45 --- /dev/null +++ b/doc/bn.doc @@ -0,0 +1,379 @@ +The Big Number library. + +#include "bn.h" when using this library. + +This big number library was written for use in implementing the RSA and DH +public key encryption algorithms. As such, features such as negative +numbers have not been extensively tested but they should work as expected. +This library uses dynamic memory allocation for storing its data structures +and so there are no limit on the size of the numbers manipulated by these +routines but there is always the requirement to check return codes from +functions just in case a memory allocation error has occurred. + +The basic object in this library is a BIGNUM. It is used to hold a single +large integer. This type should be considered opaque and fields should not +be modified or accessed directly. +typedef struct bignum_st + { + int top; /* Index of last used d. */ + BN_ULONG *d; /* Pointer to an array of 'BITS2' bit chunks. */ + int max; /* Size of the d array. */ + int neg; + } BIGNUM; +The big number is stored in a malloced array of BN_ULONG's. A BN_ULONG can +be either 16, 32 or 64 bits in size, depending on the 'number of bits' +specified in bn.h. +The 'd' field is this array. 'max' is the size of the 'd' array that has +been allocated. 'top' is the 'last' entry being used, so for a value of 4, +bn.d[0]=4 and bn.top=1. 'neg' is 1 if the number is negative. +When a BIGNUM is '0', the 'd' field can be NULL and top == 0. + +Various routines in this library require the use of 'temporary' BIGNUM +variables during their execution. Due to the use of dynamic memory +allocation to create BIGNUMs being rather expensive when used in +conjunction with repeated subroutine calls, the BN_CTX structure is +used. This structure contains BN_CTX BIGNUMs. BN_CTX +is the maximum number of temporary BIGNUMs any publicly exported +function will use. + +#define BN_CTX 12 +typedef struct bignum_ctx + { + int tos; /* top of stack */ + BIGNUM *bn[BN_CTX]; /* The variables */ + } BN_CTX; + +The functions that follow have been grouped according to function. Most +arithmetic functions return a result in the first argument, sometimes this +first argument can also be an input parameter, sometimes it cannot. These +restrictions are documented. + +extern BIGNUM *BN_value_one; +There is one variable defined by this library, a BIGNUM which contains the +number 1. This variable is useful for use in comparisons and assignment. + +Get Size functions. + +int BN_num_bits(BIGNUM *a); + This function returns the size of 'a' in bits. + +int BN_num_bytes(BIGNUM *a); + This function (macro) returns the size of 'a' in bytes. + For conversion of BIGNUMs to byte streams, this is the number of + bytes the output string will occupy. If the output byte + format specifies that the 'top' bit indicates if the number is + signed, so an extra '0' byte is required if the top bit on a + positive number is being written, it is upto the application to + make this adjustment. Like I said at the start, I don't + really support negative numbers :-). + +Creation/Destruction routines. + +BIGNUM *BN_new(); + Return a new BIGNUM object. The number initially has a value of 0. If + there is an error, NULL is returned. + +void BN_free(BIGNUM *a); + Free()s a BIGNUM. + +void BN_clear(BIGNUM *a); + Sets 'a' to a value of 0 and also zeros all unused allocated + memory. This function is used to clear a variable of 'sensitive' + data that was held in it. + +void BN_clear_free(BIGNUM *a); + This function zeros the memory used by 'a' and then free()'s it. + This function should be used to BN_free() BIGNUMS that have held + sensitive numeric values like RSA private key values. Both this + function and BN_clear tend to only be used by RSA and DH routines. + +BN_CTX *BN_CTX_new(void); + Returns a new BN_CTX. NULL on error. + +void BN_CTX_free(BN_CTX *c); + Free a BN_CTX structure. The BIGNUMs in 'c' are BN_clear_free()ed. + +BIGNUM *bn_expand(BIGNUM *b, int bits); + This is an internal function that should not normally be used. It + ensures that 'b' has enough room for a 'bits' bit number. It is + mostly used by the various BIGNUM routines. If there is an error, + NULL is returned. if not, 'b' is returned. + +BIGNUM *BN_copy(BIGNUM *to, BIGNUM *from); + The 'from' is copied into 'to'. NULL is returned if there is an + error, otherwise 'to' is returned. + +BIGNUM *BN_dup(BIGNUM *a); + A new BIGNUM is created and returned containing the value of 'a'. + NULL is returned on error. + +Comparison and Test Functions. + +int BN_is_zero(BIGNUM *a) + Return 1 if 'a' is zero, else 0. + +int BN_is_one(a) + Return 1 is 'a' is one, else 0. + +int BN_is_word(a,w) + Return 1 if 'a' == w, else 0. 'w' is a BN_ULONG. + +int BN_cmp(BIGNUM *a, BIGNUM *b); + Return -1 if 'a' is less than 'b', 0 if 'a' and 'b' are the same + and 1 is 'a' is greater than 'b'. This is a signed comparison. + +int BN_ucmp(BIGNUM *a, BIGNUM *b); + This function is the same as BN_cmp except that the comparison + ignores the sign of the numbers. + +Arithmetic Functions +For all of these functions, 0 is returned if there is an error and 1 is +returned for success. The return value should always be checked. eg. +if (!BN_add(r,a,b)) goto err; +Unless explicitly mentioned, the 'return' value can be one of the +'parameters' to the function. + +int BN_add(BIGNUM *r, BIGNUM *a, BIGNUM *b); + Add 'a' and 'b' and return the result in 'r'. This is r=a+b. + +int BN_sub(BIGNUM *r, BIGNUM *a, BIGNUM *b); + Subtract 'a' from 'b' and put the result in 'r'. This is r=a-b. + +int BN_lshift(BIGNUM *r, BIGNUM *a, int n); + Shift 'a' left by 'n' bits. This is r=a*(2^n). + +int BN_lshift1(BIGNUM *r, BIGNUM *a); + Shift 'a' left by 1 bit. This form is more efficient than + BN_lshift(r,a,1). This is r=a*2. + +int BN_rshift(BIGNUM *r, BIGNUM *a, int n); + Shift 'a' right by 'n' bits. This is r=int(a/(2^n)). + +int BN_rshift1(BIGNUM *r, BIGNUM *a); + Shift 'a' right by 1 bit. This form is more efficient than + BN_rshift(r,a,1). This is r=int(a/2). + +int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b); + Multiply a by b and return the result in 'r'. 'r' must not be + either 'a' or 'b'. It has to be a different BIGNUM. + This is r=a*b. + +int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx); + Multiply a by a and return the result in 'r'. 'r' must not be + 'a'. This function is alot faster than BN_mul(r,a,a). This is r=a*a. + +int BN_div(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx); + Divide 'm' by 'd' and return the result in 'dv' and the remainder + in 'rem'. Either of 'dv' or 'rem' can be NULL in which case that + value is not returned. 'ctx' needs to be passed as a source of + temporary BIGNUM variables. + This is dv=int(m/d), rem=m%d. + +int BN_mod(BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx); + Find the remainder of 'm' divided by 'd' and return it in 'rem'. + 'ctx' holds the temporary BIGNUMs required by this function. + This function is more efficient than BN_div(NULL,rem,m,d,ctx); + This is rem=m%d. + +int BN_mod_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BIGNUM *m,BN_CTX *ctx); + Multiply 'a' by 'b' and return the remainder when divided by 'm'. + 'ctx' holds the temporary BIGNUMs required by this function. + This is r=(a*b)%m. + +int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m,BN_CTX *ctx); + Raise 'a' to the 'p' power and return the remainder when divided by + 'm'. 'ctx' holds the temporary BIGNUMs required by this function. + This is r=(a^p)%m. + +int BN_reciprocal(BIGNUM *r, BIGNUM *m, BN_CTX *ctx); + Return the reciprocal of 'm'. 'ctx' holds the temporary variables + required. This function returns -1 on error, otherwise it returns + the number of bits 'r' is shifted left to make 'r' into an integer. + This number of bits shifted is required in BN_mod_mul_reciprocal(). + This is r=(1/m)<<(BN_num_bits(m)+1). + +int BN_mod_mul_reciprocal(BIGNUM *r, BIGNUM *x, BIGNUM *y, BIGNUM *m, + BIGNUM *i, int nb, BN_CTX *ctx); + This function is used to perform an efficient BN_mod_mul() + operation. If one is going to repeatedly perform BN_mod_mul() with + the same modulus is worth calculating the reciprocal of the modulus + and then using this function. This operation uses the fact that + a/b == a*r where r is the reciprocal of b. On modern computers + multiplication is very fast and big number division is very slow. + 'x' is multiplied by 'y' and then divided by 'm' and the remainder + is returned. 'i' is the reciprocal of 'm' and 'nb' is the number + of bits as returned from BN_reciprocal(). Normal usage is as follows. + bn=BN_reciprocal(i,m); + for (...) + { BN_mod_mul_reciprocal(r,x,y,m,i,bn,ctx); } + This is r=(x*y)%m. Internally it is approximately + r=(x*y)-m*(x*y/m) or r=(x*y)-m*((x*y*i) >> bn) + This function is used in BN_mod_exp() and BN_is_prime(). + +Assignment Operations + +int BN_one(BIGNUM *a) + Set 'a' to hold the value one. + This is a=1. + +int BN_zero(BIGNUM *a) + Set 'a' to hold the value zero. + This is a=0. + +int BN_set_word(BIGNUM *a, unsigned long w); + Set 'a' to hold the value of 'w'. 'w' is an unsigned long. + This is a=w. + +unsigned long BN_get_word(BIGNUM *a); + Returns 'a' in an unsigned long. Not remarkably, often 'a' will + be biger than a word, in which case 0xffffffffL is returned. + +Word Operations +These functions are much more efficient that the normal bignum arithmetic +operations. + +BN_ULONG BN_mod_word(BIGNUM *a, unsigned long w); + Return the remainder of 'a' divided by 'w'. + This is return(a%w). + +int BN_add_word(BIGNUM *a, unsigned long w); + Add 'w' to 'a'. This function does not take the sign of 'a' into + account. This is a+=w; + +Bit operations. + +int BN_is_bit_set(BIGNUM *a, int n); + This function return 1 if bit 'n' is set in 'a' else 0. + +int BN_set_bit(BIGNUM *a, int n); + This function sets bit 'n' to 1 in 'a'. Return 0 if less than + 'n' bits in 'a', else 1. This is a&= ~(1<<n); + +int BN_clear_bit(BIGNUM *a, int n); + This function sets bit 'n' to zero in 'a'. Return 0 if less + than 'n' bits in 'a' else 1. This is a&= ~(1<<n); + +int BN_mask_bits(BIGNUM *a, int n); + Truncate 'a' to n bits long. This is a&= ~((~0)<<n) + +Format conversion routines. + +BIGNUM *BN_bin2bn(unsigned char *s, int len,BIGNUM *ret); + This function converts 'len' bytes in 's' into a BIGNUM which + is put in 'ret'. If ret is NULL, a new BIGNUM is created. + Either this new BIGNUM or ret is returned. The number is + assumed to be in bigendian form in 's'. By this I mean that + to 'ret' is created as follows for 'len' == 5. + ret = s[0]*2^32 + s[1]*2^24 + s[2]*2^16 + s[3]*2^8 + s[4]; + This function cannot be used to convert negative numbers. It + is always assumed the number is positive. The application + needs to diddle the 'neg' field of th BIGNUM its self. + The better solution would be to save the numbers in ASN.1 format + since this is a defined standard for storing big numbers. + Look at the functions + + ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *bn, ASN1_INTEGER *ai); + BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *ai,BIGNUM *bn); + int i2d_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); + ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a,unsigned char **pp, + long length; + +int BN_bn2bin(BIGNUM *a, unsigned char *to); + This function converts 'a' to a byte string which is put into + 'to'. The representation is big-endian in that the most + significant byte of 'a' is put into to[0]. This function + returns the number of bytes used to hold 'a'. BN_num_bytes(a) + would return the same value and can be used to determine how + large 'to' needs to be. If the number is negative, this + information is lost. Since this library was written to + manipulate large positive integers, the inability to save and + restore them is not considered to be a problem by me :-). + As for BN_bin2bn(), look at the ASN.1 integer encoding funtions + for SSLeay. They use BN_bin2bn() and BN_bn2bin() internally. + +char *BN_bn2ascii(BIGNUM *a); + This function returns a malloc()ed string that contains the + ascii hexadecimal encoding of 'a'. The number is in bigendian + format with a '-' in front if the number is negative. + +int BN_ascii2bn(BIGNUM **bn, char *a); + The inverse of BN_bn2ascii. The function returns the number of + characters from 'a' were processed in generating a the bignum. + error is inticated by 0 being returned. The number is a + hex digit string, optionally with a leading '-'. If *bn + is null, a BIGNUM is created and returned via that variable. + +int BN_print_fp(FILE *fp, BIGNUM *a); + 'a' is printed to file pointer 'fp'. It is in the same format + that is output from BN_bn2ascii(). 0 is returned on error, + 1 if things are ok. + +int BN_print(BIO *bp, BIGNUM *a); + Same as BN_print except that the output is done to the SSLeay libraries + BIO routines. BN_print_fp() actually calls this function. + +Miscellaneous Routines. + +int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); + This function returns in 'rnd' a random BIGNUM that is bits + long. If bottom is 1, the number returned is odd. If top is set, + the top 2 bits of the number are set. This is useful because if + this is set, 2 'n; bit numbers multiplied together will return a 2n + bit number. If top was not set, they could produce a 2n-1 bit + number. + +BIGNUM *BN_mod_inverse(BIGNUM *a, BIGNUM *n,BN_CTX *ctx); + This function create a new BIGNUM and returns it. This number + is the inverse mod 'n' of 'a'. By this it is meant that the + returned value 'r' satisfies (a*r)%n == 1. This function is + used in the generation of RSA keys. 'ctx', as per usual, + is used to hold temporary variables that are required by the + function. NULL is returned on error. + +int BN_gcd(BIGNUM *r,BIGNUM *a,BIGNUM *b,BN_CTX *ctx); + 'r' has the greatest common divisor of 'a' and 'b'. 'ctx' is + used for temporary variables and 0 is returned on error. + +int BN_is_prime(BIGNUM *p,int nchecks,void (*callback)(),BN_CTX *ctx); + This function is used to check if a BIGNUM ('p') is prime. + It performs this test by using the Miller-Rabin randomised + primality test. This is a probalistic test that requires a + number of rounds to ensure the number is prime to a high + degree of probability. Since this can take quite some time, a + callback function can be passed and it will be called each + time 'p' passes a round of the prime testing. 'callback' will + be called as follows, callback(1,n) where n is the number of + the round, just passed. As per usual 'ctx' contains temporary + variables used. If ctx is NULL, it does not matter, a local version + will be malloced. This parameter is present to save some mallocing + inside the function but probably could be removed. + 0 is returned on error. + 'ncheck' is the number of Miller-Rabin tests to run. It is + suggested to use the value 'BN_prime_checks' by default. + +BIGNUM *BN_generate_prime( +int bits, +int strong, +BIGNUM *a, +BIGNUM *rems, +void (*callback)()); + This function is used to generate prime numbers. It returns a + new BIGNUM that has a high probability of being a prime. + 'bits' is the number of bits that + are to be in the prime. If 'strong' is true, the returned prime + will also be a strong prime ((p-1)/2 is also prime). + While searching for the prime ('p'), we + can add the requirement that the prime fill the following + condition p%a == rem. This can be used to help search for + primes with specific features, which is required when looking + for primes suitable for use with certain 'g' values in the + Diffie-Hellman key exchange algorithm. If 'a' is NULL, + this condition is not checked. If rem is NULL, rem is assumed + to be 1. Since this search for a prime + can take quite some time, if callback is not NULL, it is called + in the following situations. + We have a suspected prime (from a quick sieve), + callback(0,sus_prime++). Each item to be passed to BN_is_prime(). + callback(1,round++). Each successful 'round' in BN_is_prime(). + callback(2,round). For each successful BN_is_prime() test. + diff --git a/doc/ca.1 b/doc/ca.1 new file mode 100644 index 0000000000..5b0c5a198d --- /dev/null +++ b/doc/ca.1 @@ -0,0 +1,121 @@ +From eay@orb.mincom.oz.au Thu Dec 28 23:56:45 1995 +Received: by orb.mincom.oz.au id AA07374 + (5.65c/IDA-1.4.4 for eay); Thu, 28 Dec 1995 13:56:45 +1000 +Date: Thu, 28 Dec 1995 13:56:45 +1000 (EST) +From: Eric Young <eay@mincom.oz.au> +X-Sender: eay@orb +To: sameer <sameer@c2.org> +Cc: ssleay@mincom.oz.au +Subject: Re: 'ca' +In-Reply-To: <199512230440.UAA23410@infinity.c2.org> +Message-Id: <Pine.SOL.3.91.951228133525.7269A-100000@orb> +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Status: RO +X-Status: + +On Fri, 22 Dec 1995, sameer wrote: +> I could use documentation on 'ca'. Thanks. + +Very quickly. +The ca program uses the ssleay.conf file for most of its configuration + +./ca -help + + -verbose - Talk alot while doing things + -config file - A config file. If you don't want to use the + default config file + -name arg - The particular CA definition to use + In the config file, the section to use for parameters. This lets + multiple setups to be contained in the one file. By default, the + default_ca variable is looked up in the [ ca ] section. So in the + shipped ssleay.conf, the CA definition used is CA_default. It could be + any other name. + -gencrl days - Generate a new CRL, days is when the next CRL is due + This will generate a new certificate revocion list. + -days arg - number of days to certify the certificate for + When certifiying certificates, this is the number of days to use. + -md arg - md to use, one of md2, md5, sha or sha1 + -policy arg - The CA 'policy' to support + I'll describe this later, but there are 2 policies definied in the + shipped ssleay.conf + -keyfile arg - PEM RSA private key file + -key arg - key to decode the RSA private key if it is encrypted + since we need to keep the CA's RSA key encrypted + -cert - The CA certificate + -in file - The input PEM encoded certificate request(s) + -out file - Where to put the output file(s) + -outdir dir - Where to put output certificates + The -out options concatinates all the output certificied + certificates to one file, -outdir puts them in a directory, + named by serial number. + -infiles .... - The last argument, requests to process + The certificate requests to process, -in is the same. + +Just about all the above have default values defined in ssleay.conf. + +The key variables in ssleay.conf are (for the pariticular '-name' being +used, in the default, it is CA_default). + +dir is where all the CA database stuff is kept. +certs is where all the previously issued certificates are kept. +The database is a simple text database containing the following tab separated +fields. +status: a value of 'R' - revoked, 'E' -expired or 'V' valid. +issued date: When the certificate was certified. +revoked date: When it was revoked, blank if not revoked. +serial number: The certificate serial number. +certificate: Where the certificate is located. +CN: The name of the certificate. + +The demo file has quite a few made up values it it. The last 2 were +added by the ca program and are acurate. +The CA program does not update the 'certificate' file correctly right now. +The serial field should be unique as should the CN/status combination. +The ca program checks these at startup. What still needs to be +wrtten is a program to 'regenerate' the data base file from the issued +certificate list (and a CRL list). + +Back to the CA_default variables. + +Most of the variables are commented. + +policy is the default policy. + +Ok for policies, they define the order and which fields must be present +in the certificate request and what gets filled in. + +So a value of +countryName = match +means that the country name must match the CA certificate. +organizationalUnitName = optional +The org.Unit,Name does not have to be present and +commonName = supplied +commonName must be supplied in the certificate request. + +For the 'policy_match' polocy, the order of the attributes in the +generated certiticate would be +countryName +stateOrProvinceName +organizationName +organizationalUnitName +commonName +emailAddress + +Have a play, it sort of makes sense. If you think about how the persona +requests operate, it is similar to the 'policy_match' policy and the +'policy_anything' is similar to what versign is doing. + +I hope this helps a bit. Some backend scripts are definitly needed to +update the database and to make certificate revocion easy. All +certificates issued should also be kept forever (or until they expire?) + +hope this helps +eric (who has to run off an buy some cheap knee pads for the caving in 4 +days time :-) + +-- +Eric Young | Signature removed since it was generating +AARNet: eay@mincom.oz.au | more followups than the message contents :-) + + diff --git a/doc/callback.doc b/doc/callback.doc new file mode 100644 index 0000000000..7ad0f7f7d2 --- /dev/null +++ b/doc/callback.doc @@ -0,0 +1,240 @@ +Callback functions used in SSLeay. + +-------------------------- +The BIO library. + +Each BIO structure can have a callback defined against it. This callback is +called 2 times for each BIO 'function'. It is passed 6 parameters. +BIO_debug_callback() is an example callback which is defined in +crypto/buffer/bio_cb.c and is used in apps/dgst.c This is intended mostly +for debuging or to notify the application of IO. + +long BIO_debug_callback(BIO *bio,int cmd,char *argp,int argi,long argl, + long ret); +bio is the BIO being called, cmd is the type of BIO function being called. +Look at the BIO_CB_* defines in buffer.h. Argp and argi are the arguments +passed to BIO_read(), BIO_write, BIO_gets(), BIO_puts(). In the case of +BIO_ctrl(), argl is also defined. The first time the callback is called, +before the underlying function has been executed, 0 is passed as 'ret', and +if the return code from the callback is not > 0, the call is aborted +and the returned <= 0 value is returned. +The second time the callback is called, the 'cmd' value also has +BIO_CB_RETURN logically 'or'ed with it. The 'ret' value is the value returned +from the actuall function call and whatever the callback returns is returned +from the BIO function. + +BIO_set_callback(b,cb) can be used to set the callback function +(b is a BIO), and BIO_set_callback_arg(b,arg) can be used to +set the cb_arg argument in the BIO strucutre. This field is only intended +to be used by application, primarily in the callback function since it is +accessable since the BIO is passed. + +-------------------------- +The PEM library. + +The pem library only really uses one type of callback, +static int def_callback(char *buf, int num, int verify); +which is used to return a password string if required. +'buf' is the buffer to put the string in. 'num' is the size of 'buf' +and 'verify' is used to indicate that the password should be checked. +This last flag is mostly used when reading a password for encryption. + +For all of these functions, a NULL callback will call the above mentioned +default callback. This default function does not work under Windows 3.1. +For other machines, it will use an application defined prompt string +(EVP_set_pw_prompt(), which defines a library wide prompt string) +if defined, otherwise it will use it's own PEM password prompt. +It will then call EVP_read_pw_string() to get a password from the console. +If your application wishes to use nice fancy windows to retrieve passwords, +replace this function. The callback should return the number of bytes read +into 'buf'. If the number of bytes <= 0, it is considered an error. + +Functions that take this callback are listed below. For the 'read' type +functions, the callback will only be required if the PEM data is encrypted. + +For the Write functions, normally a password can be passed in 'kstr', of +'klen' bytes which will be used if the 'enc' cipher is not NULL. If +'kstr' is NULL, the callback will be used to retrieve a password. + +int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len, + int (*callback)()); +char *PEM_ASN1_read_bio(char *(*d2i)(),char *name,BIO *bp,char **x,int (*cb)()); +char *PEM_ASN1_read(char *(*d2i)(),char *name,FILE *fp,char **x,int (*cb)()); +int PEM_ASN1_write_bio(int (*i2d)(),char *name,BIO *bp,char *x, + EVP_CIPHER *enc,unsigned char *kstr,int klen,int (*callback)()); +int PEM_ASN1_write(int (*i2d)(),char *name,FILE *fp,char *x, + EVP_CIPHER *enc,unsigned char *kstr,int klen,int (*callback)()); +STACK *PEM_X509_INFO_read(FILE *fp, STACK *sk, int (*cb)()); +STACK *PEM_X509_INFO_read_bio(BIO *fp, STACK *sk, int (*cb)()); + +#define PEM_write_RSAPrivateKey(fp,x,enc,kstr,klen,cb) +#define PEM_write_DSAPrivateKey(fp,x,enc,kstr,klen,cb) +#define PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb) +#define PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb) +#define PEM_read_SSL_SESSION(fp,x,cb) +#define PEM_read_X509(fp,x,cb) +#define PEM_read_X509_REQ(fp,x,cb) +#define PEM_read_X509_CRL(fp,x,cb) +#define PEM_read_RSAPrivateKey(fp,x,cb) +#define PEM_read_DSAPrivateKey(fp,x,cb) +#define PEM_read_PrivateKey(fp,x,cb) +#define PEM_read_PKCS7(fp,x,cb) +#define PEM_read_DHparams(fp,x,cb) +#define PEM_read_bio_SSL_SESSION(bp,x,cb) +#define PEM_read_bio_X509(bp,x,cb) +#define PEM_read_bio_X509_REQ(bp,x,cb) +#define PEM_read_bio_X509_CRL(bp,x,cb) +#define PEM_read_bio_RSAPrivateKey(bp,x,cb) +#define PEM_read_bio_DSAPrivateKey(bp,x,cb) +#define PEM_read_bio_PrivateKey(bp,x,cb) +#define PEM_read_bio_PKCS7(bp,x,cb) +#define PEM_read_bio_DHparams(bp,x,cb) +int i2d_Netscape_RSA(RSA *a, unsigned char **pp, int (*cb)()); +RSA *d2i_Netscape_RSA(RSA **a, unsigned char **pp, long length, int (*cb)()); + +Now you will notice that macros like +#define PEM_write_X509(fp,x) \ + PEM_ASN1_write((int (*)())i2d_X509,PEM_STRING_X509,fp, \ + (char *)x, NULL,NULL,0,NULL) +Don't do encryption normally. If you want to PEM encrypt your X509 structure, +either just call PEM_ASN1_write directly or just define you own +macro variant. As you can see, this macro just sets all encryption related +parameters to NULL. + + +-------------------------- +The SSL library. + +#define SSL_set_info_callback(ssl,cb) +#define SSL_CTX_set_info_callback(ctx,cb) +void callback(SSL *ssl,int location,int ret) +This callback is called each time around the SSL_connect()/SSL_accept() +state machine. So it will be called each time the SSL protocol progresses. +It is mostly present for use when debugging. When SSL_connect() or +SSL_accept() return, the location flag is SSL_CB_ACCEPT_EXIT or +SSL_CB_CONNECT_EXIT and 'ret' is the value about to be returned. +Have a look at the SSL_CB_* defines in ssl.h. If an info callback is defined +against the SSL_CTX, it is called unless there is one set against the SSL. +Have a look at +void client_info_callback() in apps/s_client() for an example. + +Certificate verification. +void SSL_set_verify(SSL *s, int mode, int (*callback) ()); +void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*callback)()); +This callback is used to help verify client and server X509 certificates. +It is actually passed to X509_cert_verify(), along with the SSL structure +so you have to read about X509_cert_verify() :-). The SSL_CTX version is used +if the SSL version is not defined. X509_cert_verify() is the function used +by the SSL part of the library to verify certificates. This function is +nearly always defined by the application. + +void SSL_CTX_set_cert_verify_cb(SSL_CTX *ctx, int (*cb)(),char *arg); +int callback(char *arg,SSL *s,X509 *xs,STACK *cert_chain); +This call is used to replace the SSLeay certificate verification code. +The 'arg' is kept in the SSL_CTX and is passed to the callback. +If the callback returns 0, the certificate is rejected, otherwise it +is accepted. The callback is replacing the X509_cert_verify() call. +This feature is not often used, but if you wished to implement +some totally different certificate authentication system, this 'hook' is +vital. + +SSLeay keeps a cache of session-ids against each SSL_CTX. These callbacks can +be used to notify the application when a SSL_SESSION is added to the cache +or to retrieve a SSL_SESSION that is not in the cache from the application. +#define SSL_CTX_sess_set_get_cb(ctx,cb) +SSL_SESSION *callback(SSL *s,char *session_id,int session_id_len,int *copy); +If defined, this callback is called to return the SESSION_ID for the +session-id in 'session_id', of 'session_id_len' bytes. 'copy' is set to 1 +if the server is to 'take a copy' of the SSL_SESSION structure. It is 0 +if the SSL_SESSION is being 'passed in' so the SSLeay library is now +responsible for 'free()ing' the structure. Basically it is used to indicate +if the reference count on the SSL_SESSION structure needs to be incremented. + +#define SSL_CTX_sess_set_new_cb(ctx,cb) +int callback(SSL *s, SSL_SESSION *sess); +When a new connection is established, if the SSL_SESSION is going to be added +to the cache, this callback is called. Return 1 if a 'copy' is required, +otherwise, return 0. This return value just causes the reference count +to be incremented (on return of a 1), this means the application does +not need to worry about incrementing the refernece count (and the +locking that implies in a multi-threaded application). + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx,int (*cb)()); +This sets the SSL password reading function. +It is mostly used for windowing applications +and used by PEM_read_bio_X509() and PEM_read_bio_RSAPrivateKey() +calls inside the SSL library. The only reason this is present is because the +calls to PEM_* functions is hidden in the SSLeay library so you have to +pass in the callback some how. + +#define SSL_CTX_set_client_cert_cb(ctx,cb) +int callback(SSL *s,X509 **x509, EVP_PKEY **pkey); +Called when a client certificate is requested but there is not one set +against the SSL_CTX or the SSL. If the callback returns 1, x509 and +pkey need to point to valid data. The library will free these when +required so if the application wants to keep these around, increment +their reference counts. If 0 is returned, no client cert is +available. If -1 is returned, it is assumed that the callback needs +to be called again at a later point in time. SSL_connect will return +-1 and SSL_want_x509_lookup(ssl) returns true. Remember that +application data can be attached to an SSL structure via the +SSL_set_app_data(SSL *ssl,char *data) call. + +-------------------------- +The X509 library. + +int X509_cert_verify(CERTIFICATE_CTX *ctx,X509 *xs, int (*cb)(), + int *error,char *arg,STACK *cert_chain); +int verify_callback(int ok,X509 *xs,X509 *xi,int depth,int error,char *arg, + STACK *cert_chain); + +X509_cert_verify() is used to authenticate X509 certificates. The 'ctx' holds +the details of the various caches and files used to locate certificates. +'xs' is the certificate to verify and 'cb' is the application callback (more +detail later). 'error' will be set to the error code and 'arg' is passed +to the 'cb' callback. Look at the VERIFY_* defines in crypto/x509/x509.h + +When ever X509_cert_verify() makes a 'negative' decision about a +certitificate, the callback is called. If everything checks out, the +callback is called with 'VERIFY_OK' or 'VERIFY_ROOT_OK' (for a self +signed cert that is not the passed certificate). + +The callback is passed the X509_cert_verify opinion of the certificate +in 'ok', the certificate in 'xs', the issuer certificate in 'xi', +the 'depth' of the certificate in the verification 'chain', the +VERIFY_* code in 'error' and the argument passed to X509_cert_verify() +in 'arg'. cert_chain is a list of extra certs to use if they are not +in the cache. + +The callback can be used to look at the error reason, and then return 0 +for an 'error' or '1' for ok. This will override the X509_cert_verify() +opinion of the certificates validity. Processing will continue depending on +the return value. If one just wishes to use the callback for informational +reason, just return the 'ok' parameter. + +-------------------------- +The BN and DH library. + +BIGNUM *BN_generate_prime(int bits,int strong,BIGNUM *add, + BIGNUM *rem,void (*callback)(int,int)); +int BN_is_prime(BIGNUM *p,int nchecks,void (*callback)(int,int), + +Read doc/bn.doc for the description of these 2. + +DH *DH_generate_parameters(int prime_len,int generator, + void (*callback)(int,int)); +Read doc/bn.doc for the description of the callback, since it is just passed +to BN_generate_prime(), except that it is also called as +callback(3,0) by this function. + +-------------------------- +The CRYPTO library. + +void CRYPTO_set_locking_callback(void (*func)(int mode,int type,char *file, + int line)); +void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount, + int type,char *file, int line)); +void CRYPTO_set_id_callback(unsigned long (*func)(void)); + +Read threads.doc for info on these ones. + diff --git a/doc/cipher.doc b/doc/cipher.doc new file mode 100644 index 0000000000..d49ba78c5c --- /dev/null +++ b/doc/cipher.doc @@ -0,0 +1,345 @@ +The Cipher subroutines. + +These routines require "evp.h" to be included. + +These functions are a higher level interface to the various cipher +routines found in this library. As such, they allow the same code to be +used to encrypt and decrypt via different ciphers with only a change +in an initial parameter. These routines also provide buffering for block +ciphers. + +These routines all take a pointer to the following structure to specify +which cipher to use. If you wish to use a new cipher with these routines, +you would probably be best off looking an how an existing cipher is +implemented and copying it. At this point in time, I'm not going to go +into many details. This structure should be considered opaque + +typedef struct pem_cipher_st + { + int type; + int block_size; + int key_len; + int iv_len; + void (*enc_init)(); /* init for encryption */ + void (*dec_init)(); /* init for decryption */ + void (*do_cipher)(); /* encrypt data */ + } EVP_CIPHER; + +The type field is the object NID of the cipher type +(read the section on Objects for an explanation of what a NID is). +The cipher block_size is how many bytes need to be passed +to the cipher at a time. Key_len is the +length of the key the cipher requires and iv_len is the length of the +initialisation vector required. enc_init is the function +called to initialise the ciphers context for encryption and dec_init is the +function to initialise for decryption (they need to be different, especially +for the IDEA cipher). + +One reason for specifying the Cipher via a pointer to a structure +is that if you only use des-cbc, only the des-cbc routines will +be included when you link the program. If you passed an integer +that specified which cipher to use, the routine that mapped that +integer to a set of cipher functions would cause all the ciphers +to be link into the code. This setup also allows new ciphers +to be added by the application (with some restrictions). + +The thirteen ciphers currently defined in this library are + +EVP_CIPHER *EVP_des_ecb(); /* DES in ecb mode, iv=0, block=8, key= 8 */ +EVP_CIPHER *EVP_des_ede(); /* DES in ecb ede mode, iv=0, block=8, key=16 */ +EVP_CIPHER *EVP_des_ede3(); /* DES in ecb ede mode, iv=0, block=8, key=24 */ +EVP_CIPHER *EVP_des_cfb(); /* DES in cfb mode, iv=8, block=1, key= 8 */ +EVP_CIPHER *EVP_des_ede_cfb(); /* DES in ede cfb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_des_ede3_cfb();/* DES in ede cfb mode, iv=8, block=1, key=24 */ +EVP_CIPHER *EVP_des_ofb(); /* DES in ofb mode, iv=8, block=1, key= 8 */ +EVP_CIPHER *EVP_des_ede_ofb(); /* DES in ede ofb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_des_ede3_ofb();/* DES in ede ofb mode, iv=8, block=1, key=24 */ +EVP_CIPHER *EVP_des_cbc(); /* DES in cbc mode, iv=8, block=8, key= 8 */ +EVP_CIPHER *EVP_des_ede_cbc(); /* DES in cbc ede mode, iv=8, block=8, key=16 */ +EVP_CIPHER *EVP_des_ede3_cbc();/* DES in cbc ede mode, iv=8, block=8, key=24 */ +EVP_CIPHER *EVP_desx_cbc(); /* DES in desx cbc mode,iv=8, block=8, key=24 */ +EVP_CIPHER *EVP_rc4(); /* RC4, iv=0, block=1, key=16 */ +EVP_CIPHER *EVP_idea_ecb(); /* IDEA in ecb mode, iv=0, block=8, key=16 */ +EVP_CIPHER *EVP_idea_cfb(); /* IDEA in cfb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_idea_ofb(); /* IDEA in ofb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_idea_cbc(); /* IDEA in cbc mode, iv=8, block=8, key=16 */ +EVP_CIPHER *EVP_rc2_ecb(); /* RC2 in ecb mode, iv=0, block=8, key=16 */ +EVP_CIPHER *EVP_rc2_cfb(); /* RC2 in cfb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_rc2_ofb(); /* RC2 in ofb mode, iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_rc2_cbc(); /* RC2 in cbc mode, iv=8, block=8, key=16 */ +EVP_CIPHER *EVP_bf_ecb(); /* Blowfish in ecb mode,iv=0, block=8, key=16 */ +EVP_CIPHER *EVP_bf_cfb(); /* Blowfish in cfb mode,iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_bf_ofb(); /* Blowfish in ofb mode,iv=8, block=1, key=16 */ +EVP_CIPHER *EVP_bf_cbc(); /* Blowfish in cbc mode,iv=8, block=8, key=16 */ + +The meaning of the compound names is as follows. +des The base cipher is DES. +idea The base cipher is IDEA +rc4 The base cipher is RC4-128 +rc2 The base cipher is RC2-128 +ecb Electronic Code Book form of the cipher. +cbc Cipher Block Chaining form of the cipher. +cfb 64 bit Cipher Feedback form of the cipher. +ofb 64 bit Output Feedback form of the cipher. +ede The cipher is used in Encrypt, Decrypt, Encrypt mode. The first + and last keys are the same. +ede3 The cipher is used in Encrypt, Decrypt, Encrypt mode. + +All the Cipher routines take a EVP_CIPHER_CTX pointer as an argument. +The state of the cipher is kept in this structure. + +typedef struct EVP_CIPHER_Ctx_st + { + EVP_CIPHER *cipher; + int encrypt; /* encrypt or decrypt */ + int buf_len; /* number we have left */ + unsigned char buf[8]; + union { + .... /* cipher specific stuff */ + } c; + } EVP_CIPHER_CTX; + +Cipher is a pointer the the EVP_CIPHER for the current context. The encrypt +flag indicates encryption or decryption. buf_len is the number of bytes +currently being held in buf. +The 'c' union holds the cipher specify context. + +The following functions are to be used. + +int EVP_read_pw_string( +char *buf, +int len, +char *prompt, +int verify, + This function is the same as des_read_pw_string() (des.doc). + +void EVP_set_pw_prompt(char *prompt); + This function sets the 'default' prompt to use to use in + EVP_read_pw_string when the prompt parameter is NULL. If the + prompt parameter is NULL, this 'default prompt' feature is turned + off. Be warned, this is a global variable so weird things + will happen if it is used under Win16 and care must be taken + with a multi-threaded version of the library. + +char *EVP_get_pw_prompt(); + This returns a pointer to the default prompt string. NULL + if it is not set. + +int EVP_BytesToKey( +EVP_CIPHER *type, +EVP_MD *md, +unsigned char *salt, +unsigned char *data, +int datal, +int count, +unsigned char *key, +unsigned char *iv); + This function is used to generate a key and an initialisation vector + for a specified cipher from a key string and a salt. Type + specifies the cipher the 'key' is being generated for. Md is the + message digest algorithm to use to generate the key and iv. The salt + is an optional 8 byte object that is used to help seed the key + generator. + If the salt value is NULL, it is just not used. Datal is the + number of bytes to use from 'data' in the key generation. + This function returns the key size for the specified cipher, if + data is NULL, this value is returns and no other + computation is performed. Count is + the number of times to loop around the key generator. I would + suggest leaving it's value as 1. Key and iv are the structures to + place the returning iv and key in. If they are NULL, no value is + generated for that particular value. + The algorithm used is as follows + + /* M[] is an array of message digests + * MD() is the message digest function */ + M[0]=MD(data . salt); + for (i=1; i<count; i++) M[0]=MD(M[0]); + + i=1 + while (data still needed for key and iv) + { + M[i]=MD(M[i-1] . data . salt); + for (i=1; i<count; i++) M[i]=MD(M[i]); + i++; + } + + If the salt is NULL, it is not used. + The digests are concatenated together. + M = M[0] . M[1] . M[2] ....... + + For key= 8, iv=8 => key=M[0.. 8], iv=M[ 9 .. 16]. + For key=16, iv=0 => key=M[0..16]. + For key=16, iv=8 => key=M[0..16], iv=M[17 .. 24]. + For key=24, iv=8 => key=M[0..24], iv=M[25 .. 32]. + + This routine will produce DES-CBC keys and iv that are compatible + with the PKCS-5 standard when md2 or md5 are used. If md5 is + used, the salt is NULL and count is 1, this routine will produce + the password to key mapping normally used with RC4. + I have attempted to logically extend the PKCS-5 standard to + generate keys and iv for ciphers that require more than 16 bytes, + if anyone knows what the correct standard is, please inform me. + When using sha or sha1, things are a bit different under this scheme, + since sha produces a 20 byte digest. So for ciphers requiring + 24 bits of data, 20 will come from the first MD and 4 will + come from the second. + + I have considered having a separate function so this 'routine' + can be used without the requirement of passing a EVP_CIPHER *, + but I have decided to not bother. If you wish to use the + function without official EVP_CIPHER structures, just declare + a local one and set the key_len and iv_len fields to the + length you desire. + +The following routines perform encryption and decryption 'by parts'. By +this I mean that there are groups of 3 routines. An Init function that is +used to specify a cipher and initialise data structures. An Update routine +that does encryption/decryption, one 'chunk' at a time. And finally a +'Final' function that finishes the encryption/decryption process. +All these functions take a EVP_CIPHER pointer to specify which cipher to +encrypt/decrypt with. They also take a EVP_CIPHER_CTX object as an +argument. This structure is used to hold the state information associated +with the operation in progress. + +void EVP_EncryptInit( +EVP_CIPHER_CTX *ctx, +EVP_CIPHER *type, +unsigned char *key, +unsigned char *iv); + This function initialise a EVP_CIPHER_CTX for encryption using the + cipher passed in the 'type' field. The cipher is initialised to use + 'key' as the key and 'iv' for the initialisation vector (if one is + required). If the type, key or iv is NULL, the value currently in the + EVP_CIPHER_CTX is reused. So to perform several decrypt + using the same cipher, key and iv, initialise with the cipher, + key and iv the first time and then for subsequent calls, + reuse 'ctx' but pass NULL for type, key and iv. You must make sure + to pass a key that is large enough for a particular cipher. I + would suggest using the EVP_BytesToKey() function. + +void EVP_EncryptUpdate( +EVP_CIPHER_CTX *ctx, +unsigned char *out, +int *outl, +unsigned char *in, +int inl); + This function takes 'inl' bytes from 'in' and outputs bytes + encrypted by the cipher 'ctx' was initialised with into 'out'. The + number of bytes written to 'out' is put into outl. If a particular + cipher encrypts in blocks, less or more bytes than input may be + output. Currently the largest block size used by supported ciphers + is 8 bytes, so 'out' should have room for 'inl+7' bytes. Normally + EVP_EncryptInit() is called once, followed by lots and lots of + calls to EVP_EncryptUpdate, followed by a single EVP_EncryptFinal + call. + +void EVP_EncryptFinal( +EVP_CIPHER_CTX *ctx, +unsigned char *out, +int *outl); + Because quite a large number of ciphers are block ciphers, there is + often an incomplete block to write out at the end of the + encryption. EVP_EncryptFinal() performs processing on this last + block. The last block in encoded in such a way that it is possible + to determine how many bytes in the last block are valid. For 8 byte + block size ciphers, if only 5 bytes in the last block are valid, the + last three bytes will be filled with the value 3. If only 2 were + valid, the other 6 would be filled with sixes. If all 8 bytes are + valid, a extra 8 bytes are appended to the cipher stream containing + nothing but 8 eights. These last bytes are output into 'out' and + the number of bytes written is put into 'outl' These last bytes + are output into 'out' and the number of bytes written is put into + 'outl'. This form of block cipher finalisation is compatible with + PKCS-5. Please remember that even if you are using ciphers like + RC4 that has no blocking and so the function will not write + anything into 'out', it would still be a good idea to pass a + variable for 'out' that can hold 8 bytes just in case the cipher is + changed some time in the future. It should also be remembered + that the EVP_CIPHER_CTX contains the password and so when one has + finished encryption with a particular EVP_CIPHER_CTX, it is good + practice to zero the structure + (ie. memset(ctx,0,sizeof(EVP_CIPHER_CTX)). + +void EVP_DecryptInit( +EVP_CIPHER_CTX *ctx, +EVP_CIPHER *type, +unsigned char *key, +unsigned char *iv); + This function is basically the same as EVP_EncryptInit() accept that + is prepares the EVP_CIPHER_CTX for decryption. + +void EVP_DecryptUpdate( +EVP_CIPHER_CTX *ctx, +unsigned char *out, +int *outl, +unsigned char *in, +int inl); + This function is basically the same as EVP_EncryptUpdate() + except that it performs decryption. There is one + fundamental difference though. 'out' can not be the same as + 'in' for any ciphers with a block size greater than 1 if more + than one call to EVP_DecryptUpdate() will be made. This + is because this routine can hold a 'partial' block between + calls. When a partial block is decrypted (due to more bytes + being passed via this function, they will be written to 'out' + overwriting the input bytes in 'in' that have not been read + yet. From this it should also be noted that 'out' should + be at least one 'block size' larger than 'inl'. This problem + only occurs on the second and subsequent call to + EVP_DecryptUpdate() when using a block cipher. + +int EVP_DecryptFinal( +EVP_CIPHER_CTX *ctx, +unsigned char *out, +int *outl); + This function is different to EVP_EncryptFinal in that it 'removes' + any padding bytes appended when the data was encrypted. Due to the + way in which 1 to 8 bytes may have been appended when encryption + using a block cipher, 'out' can end up with 0 to 7 bytes being put + into it. When decoding the padding bytes, it is possible to detect + an incorrect decryption. If the decryption appears to be wrong, 0 + is returned. If everything seems ok, 1 is returned. For ciphers + with a block size of 1 (RC4), this function would normally not + return any bytes and would always return 1. Just because this + function returns 1 does not mean the decryption was correct. It + would normally be wrong due to either the wrong key/iv or + corruption of the cipher data fed to EVP_DecryptUpdate(). + As for EVP_EncryptFinal, it is a good idea to zero the + EVP_CIPHER_CTX after use since the structure contains the key used + to decrypt the data. + +The following Cipher routines are convenience routines that call either +EVP_EncryptXxx or EVP_DecryptXxx depending on weather the EVP_CIPHER_CTX +was setup to encrypt or decrypt. + +void EVP_CipherInit( +EVP_CIPHER_CTX *ctx, +EVP_CIPHER *type, +unsigned char *key, +unsigned char *iv, +int enc); + This function take arguments that are the same as EVP_EncryptInit() + and EVP_DecryptInit() except for the extra 'enc' flag. If 1, the + EVP_CIPHER_CTX is setup for encryption, if 0, decryption. + +void EVP_CipherUpdate( +EVP_CIPHER_CTX *ctx, +unsigned char *out, +int *outl, +unsigned char *in, +int inl); + Again this function calls either EVP_EncryptUpdate() or + EVP_DecryptUpdate() depending on state in the 'ctx' structure. + As noted for EVP_DecryptUpdate(), when this routine is used + for decryption with block ciphers, 'out' should not be the + same as 'in'. + +int EVP_CipherFinal( +EVP_CIPHER_CTX *ctx, +unsigned char *outm, +int *outl); + This routine call EVP_EncryptFinal() or EVP_DecryptFinal() + depending on the state information in 'ctx'. 1 is always returned + if the mode is encryption, otherwise the return value is the return + value of EVP_DecryptFinal(). diff --git a/doc/cipher.m b/doc/cipher.m new file mode 100644 index 0000000000..9f74917135 --- /dev/null +++ b/doc/cipher.m @@ -0,0 +1,128 @@ +From ssl-lists-owner@mincom.com Tue Oct 15 18:16:14 1996 +Received: from cygnus.mincom.oz.au by orb.mincom.oz.au with SMTP id AA11550 + (5.65c/IDA-1.4.4 for eay); Tue, 15 Oct 1996 08:17:41 +1000 +Received: (from daemon@localhost) by cygnus.mincom.oz.au (8.7.5/8.7.3) id IAA12472 for ssl-users-outgoing; Tue, 15 Oct 1996 08:16:35 +1000 (EST) +Received: from orb.mincom.oz.au (eay@orb.mincom.oz.au [192.55.197.1]) by cygnus.mincom.oz.au (8.7.5/8.7.3) with SMTP id IAA12463 for <ssl-users@listserv.mincom.oz.au>; Tue, 15 Oct 1996 08:16:32 +1000 (EST) +Received: by orb.mincom.oz.au id AA11544 + (5.65c/IDA-1.4.4 for ssl-users@listserv.mincom.oz.au); Tue, 15 Oct 1996 08:16:15 +1000 +Date: Tue, 15 Oct 1996 08:16:14 +1000 (EST) +From: Eric Young <eay@mincom.com> +X-Sender: eay@orb +To: Roland Haring <rharing@tandem.cl> +Cc: ssl-users@mincom.com +Subject: Re: Symmetric encryption with ssleay +In-Reply-To: <m0vBpyq-00001aC@tandemnet.tandem.cl> +Message-Id: <Pine.SOL.3.91.961015075623.11394A-100000@orb> +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Sender: ssl-lists-owner@mincom.com +Precedence: bulk +Status: RO +X-Status: + + +On Fri, 11 Oct 1996, Roland Haring wrote: +> THE_POINT: +> Would somebody be so kind to give me the minimum basic +> calls I need to do to libcrypto.a to get some text encrypted +> and decrypted again? ...hopefully with code included to do +> base64 encryption and decryption ... e.g. that sign-it.c code +> posted some while ago was a big help :-) (please, do not point +> me to apps/enc.c where I suspect my Heissenbug to be hidden :-) + +Ok, the base64 encoding stuff in 'enc.c' does the wrong thing sometimes +when the data is less than a line long (this is for decoding). I'll dig +up the exact fix today and post it. I am taking longer on 0.6.5 than I +intended so I'll just post this patch. + +The documentation to read is in +doc/cipher.doc, +doc/encode.doc (very sparse :-). +and perhaps +doc/digest.doc, + +The basic calls to encrypt with say triple DES are + +Given +char key[EVP_MAX_KEY_LENGTH]; +char iv[EVP_MAX_IV_LENGTH]; +EVP_CIPHER_CTX ctx; +unsigned char out[512+8]; +int outl; + +/* optional generation of key/iv data from text password using md5 + * via an upward compatable verson of PKCS#5. */ +EVP_BytesToKey(EVP_des_ede3_cbc,EVP_md5,NULL,passwd,strlen(passwd), + key,iv); + +/* Initalise the EVP_CIPHER_CTX */ +EVP_EncryptInit(ctx,EVP_des_ede3_cbc,key,iv); + +while (....) + { + /* This is processing 512 bytes at a time, the bytes are being + * copied into 'out', outl bytes are output. 'out' should not be the + * same as 'in' for reasons mentioned in the documentation. */ + EVP_EncryptUpdate(ctx,out,&outl,in,512); + } + +/* Output the last 'block'. If the cipher is a block cipher, the last + * block is encoded in such a way so that a wrong decryption will normally be + * detected - again, one of the PKCS standards. */ + +EVP_EncryptFinal(ctx,out,&outl); + +To decrypt, use the EVP_DecryptXXXXX functions except that EVP_DecryptFinal() +will return 0 if the decryption fails (only detectable on block ciphers). + +You can also use +EVP_CipherInit() +EVP_CipherUpdate() +EVP_CipherFinal() +which does either encryption or decryption depending on an extra +parameter to EVP_CipherInit(). + + +To do the base64 encoding, +EVP_EncodeInit() +EVP_EncodeUpdate() +EVP_EncodeFinal() + +EVP_DecodeInit() +EVP_DecodeUpdate() +EVP_DecodeFinal() + +where the encoding is quite simple, but the decoding can be a bit more +fun (due to dud input). + +EVP_DecodeUpdate() returns -1 for an error on an input line, 0 if the +'last line' was just processed, and 1 if more lines should be submitted. + +EVP_DecodeFinal() returns -1 for an error or 1 if things are ok. + +So the loop becomes +EVP_DecodeInit(....) +for (;;) + { + i=EVP_DecodeUpdate(....); + if (i < 0) goto err; + + /* process the data */ + + if (i == 0) break; + } +EVP_DecodeFinal(....); +/* process the data */ + +The problem in 'enc.c' is that I was stuff the processing up after the +EVP_DecodeFinal(...) when the for(..) loop was not being run (one line of +base64 data) and this was because 'enc.c' tries to scan over a file until +it hits the first valid base64 encoded line. + +hope this helps a bit. +eric +-- +Eric Young | BOOL is tri-state according to Bill Gates. +AARNet: eay@mincom.oz.au | RTFM Win32 GetMessage(). + + diff --git a/doc/conf.doc b/doc/conf.doc new file mode 100644 index 0000000000..f12fe884f5 --- /dev/null +++ b/doc/conf.doc @@ -0,0 +1,89 @@ +The CONF library. + +The CONF library is a simple set of routines that can be used to configure +programs. It is a superset of the genenv() function with some extra +structure. + +The library consists of 5 functions. + +LHASH *CONF_load(LHASH *config,char *file); +This function is called to load in a configuration file. Multiple +configuration files can be loaded, with each subsequent 'load' overwriting +any already defined 'variables'. If there is an error, NULL is returned. +If config is NULL, a new LHASH structure is created and returned, otherwise +the new data in the 'file' is loaded into the 'config' structure. + +void CONF_free(LHASH *config); +This function free()s the data in config. + +char *CONF_get_string(LHASH *config,char *section,char *name); +This function returns the string found in 'config' that corresponds to the +'section' and 'name' specified. Classes and the naming system used will be +discussed later in this document. If the variable is not defined, an NULL +is returned. + +long CONF_get_long(LHASH *config,char *section, char *name); +This function is the same as CONF_get_string() except that it converts the +string to an long and returns it. If variable is not a number or the +variable does not exist, 0 is returned. This is a little problematic but I +don't know of a simple way around it. + +STACK *CONF_get_section(LHASH *config, char *section); +This function returns a 'stack' of CONF_VALUE items that are all the +items defined in a particular section. DO NOT free() any of the +variable returned. They will disappear when CONF_free() is called. + +The 'lookup' model. +The configuration file is divided into 'sections'. Each section is started by +a line of the form '[ section ]'. All subsequent variable definitions are +of this section. A variable definition is a simple alpha-numeric name +followed by an '=' and then the data. A section or variable name can be +described by a regular expression of the following form '[A-Za-z0-9_]+'. +The value of the variable is the text after the '=' until the end of the +line, stripped of leading and trailing white space. +At this point I should mention that a '#' is a comment character, \ is the +escape character, and all three types of quote can be used to stop any +special interpretation of the data. +Now when the data is being loaded, variable expansion can occur. This is +done by expanding any $NAME sequences into the value represented by the +variable NAME. If the variable is not in the current section, the different +section can be specified by using the $SECTION::NAME form. The ${NAME} form +also works and is very useful for expanding variables inside strings. + +When a variable is looked up, there are 2 special section. 'default', which +is the initial section, and 'ENV' which is the processes environment +variables (accessed via getenv()). When a variable is looked up, it is +first 'matched' with it's section (if one was specified), if this fails, the +'default' section is matched. +If the 'lhash' variable passed was NULL, the environment is searched. + +Now why do we bother with sections? So we can have multiple programs using +the same configuration file, or multiple instances of the same program +using different variables. It also provides a nice mechanism to override +the processes environment variables (eg ENV::HOME=/tmp). If there is a +program specific variable missing, we can have default values. +Multiple configuration files can be loaded, with each new value clearing +any predefined values. A system config file can provide 'default' values, +and application/usr specific files can provide overriding values. + +Examples + +# This is a simple example +SSLEAY_HOME = /usr/local/ssl +ENV::PATH = $SSLEAY_HOME/bin:$PATH # override my path + +[X509] +cert_dir = $SSLEAY_HOME/certs # /usr/local/ssl/certs + +[SSL] +CIPHER = DES-EDE-MD5:RC4-MD5 +USER_CERT = $HOME/${USER}di'r 5' # /home/eay/eaydir 5 +USER_CERT = $HOME/\${USER}di\'r # /home/eay/${USER}di'r +USER_CERT = "$HOME/${US"ER}di\'r # $HOME/${USER}di'r + +TEST = 1234\ +5678\ +9ab # TEST=123456789ab +TTT = 1234\n\n # TTT=1234<nl><nl> + + diff --git a/doc/danger b/doc/danger new file mode 100644 index 0000000000..d71b1b7489 --- /dev/null +++ b/doc/danger @@ -0,0 +1,8 @@ +If you specify a SSLv2 cipher, and the mode is SSLv23 and the server +can talk SSLv3, it will claim there is no cipher since you should be +using SSLv3. + +When tracing debug stuff, remember BIO_s_socket() is different to +BIO_s_connect(). + +BSD/OS assember is not working diff --git a/doc/des.doc b/doc/des.doc new file mode 100644 index 0000000000..1e30158129 --- /dev/null +++ b/doc/des.doc @@ -0,0 +1,505 @@ +The DES library. + +Please note that this library was originally written to operate with +eBones, a version of Kerberos that had had encryption removed when it left +the USA and then put back in. As such there are some routines that I will +advise not using but they are still in the library for historical reasons. +For all calls that have an 'input' and 'output' variables, they can be the +same. + +This library requires the inclusion of 'des.h'. + +All of the encryption functions take what is called a des_key_schedule as an +argument. A des_key_schedule is an expanded form of the des key. +A des_key is 8 bytes of odd parity, the type used to hold the key is a +des_cblock. A des_cblock is an array of 8 bytes, often in this library +description I will refer to input bytes when the function specifies +des_cblock's as input or output, this just means that the variable should +be a multiple of 8 bytes. + +The define DES_ENCRYPT is passed to specify encryption, DES_DECRYPT to +specify decryption. The functions and global variable are as follows: + +int des_check_key; + DES keys are supposed to be odd parity. If this variable is set to + a non-zero value, des_set_key() will check that the key has odd + parity and is not one of the known weak DES keys. By default this + variable is turned off; + +void des_set_odd_parity( +des_cblock *key ); + This function takes a DES key (8 bytes) and sets the parity to odd. + +int des_is_weak_key( +des_cblock *key ); + This function returns a non-zero value if the DES key passed is a + weak, DES key. If it is a weak key, don't use it, try a different + one. If you are using 'random' keys, the chances of hitting a weak + key are 1/2^52 so it is probably not worth checking for them. + +int des_set_key( +des_cblock *key, +des_key_schedule schedule); + Des_set_key converts an 8 byte DES key into a des_key_schedule. + A des_key_schedule is an expanded form of the key which is used to + perform actual encryption. It can be regenerated from the DES key + so it only needs to be kept when encryption or decryption is about + to occur. Don't save or pass around des_key_schedule's since they + are CPU architecture dependent, DES keys are not. If des_check_key + is non zero, zero is returned if the key has the wrong parity or + the key is a weak key, else 1 is returned. + +int des_key_sched( +des_cblock *key, +des_key_schedule schedule); + An alternative name for des_set_key(). + +int des_rw_mode; /* defaults to DES_PCBC_MODE */ + This flag holds either DES_CBC_MODE or DES_PCBC_MODE (default). + This specifies the function to use in the enc_read() and enc_write() + functions. + +void des_encrypt( +unsigned long *data, +des_key_schedule ks, +int enc); + This is the DES encryption function that gets called by just about + every other DES routine in the library. You should not use this + function except to implement 'modes' of DES. I say this because the + functions that call this routine do the conversion from 'char *' to + long, and this needs to be done to make sure 'non-aligned' memory + access do not occur. The characters are loaded 'little endian', + have a look at my source code for more details on how I use this + function. + Data is a pointer to 2 unsigned long's and ks is the + des_key_schedule to use. enc, is non zero specifies encryption, + zero if decryption. + +void des_encrypt2( +unsigned long *data, +des_key_schedule ks, +int enc); + This functions is the same as des_encrypt() except that the DES + initial permutation (IP) and final permutation (FP) have been left + out. As for des_encrypt(), you should not use this function. + It is used by the routines in my library that implement triple DES. + IP() des_encrypt2() des_encrypt2() des_encrypt2() FP() is the same + as des_encrypt() des_encrypt() des_encrypt() except faster :-). + +void des_ecb_encrypt( +des_cblock *input, +des_cblock *output, +des_key_schedule ks, +int enc); + This is the basic Electronic Code Book form of DES, the most basic + form. Input is encrypted into output using the key represented by + ks. If enc is non zero (DES_ENCRYPT), encryption occurs, otherwise + decryption occurs. Input is 8 bytes long and output is 8 bytes. + (the des_cblock structure is 8 chars). + +void des_ecb3_encrypt( +des_cblock *input, +des_cblock *output, +des_key_schedule ks1, +des_key_schedule ks2, +des_key_schedule ks3, +int enc); + This is the 3 key EDE mode of ECB DES. What this means is that + the 8 bytes of input is encrypted with ks1, decrypted with ks2 and + then encrypted again with ks3, before being put into output; + C=E(ks3,D(ks2,E(ks1,M))). There is a macro, des_ecb2_encrypt() + that only takes 2 des_key_schedules that implements, + C=E(ks1,D(ks2,E(ks1,M))) in that the final encrypt is done with ks1. + +void des_cbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule ks, +des_cblock *ivec, +int enc); + This routine implements DES in Cipher Block Chaining mode. + Input, which should be a multiple of 8 bytes is encrypted + (or decrypted) to output which will also be a multiple of 8 bytes. + The number of bytes is in length (and from what I've said above, + should be a multiple of 8). If length is not a multiple of 8, I'm + not being held responsible :-). ivec is the initialisation vector. + This function does not modify this variable. To correctly implement + cbc mode, you need to do one of 2 things; copy the last 8 bytes of + cipher text for use as the next ivec in your application, + or use des_ncbc_encrypt(). + Only this routine has this problem with updating the ivec, all + other routines that are implementing cbc mode update ivec. + +void des_ncbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule sk, +des_cblock *ivec, +int enc); + For historical reasons, des_cbc_encrypt() did not update the + ivec with the value requires so that subsequent calls to + des_cbc_encrypt() would 'chain'. This was needed so that the same + 'length' values would not need to be used when decrypting. + des_ncbc_encrypt() does the right thing. It is the same as + des_cbc_encrypt accept that ivec is updates with the correct value + to pass in subsequent calls to des_ncbc_encrypt(). I advise using + des_ncbc_encrypt() instead of des_cbc_encrypt(); + +void des_xcbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule sk, +des_cblock *ivec, +des_cblock *inw, +des_cblock *outw, +int enc); + This is RSA's DESX mode of DES. It uses inw and outw to + 'whiten' the encryption. inw and outw are secret (unlike the iv) + and are as such, part of the key. So the key is sort of 24 bytes. + This is much better than cbc des. + +void des_3cbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule sk1, +des_key_schedule sk2, +des_cblock *ivec1, +des_cblock *ivec2, +int enc); + This function is flawed, do not use it. I have left it in the + library because it is used in my des(1) program and will function + correctly when used by des(1). If I removed the function, people + could end up unable to decrypt files. + This routine implements outer triple cbc encryption using 2 ks and + 2 ivec's. Use des_ede2_cbc_encrypt() instead. + +void des_ede3_cbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule ks1, +des_key_schedule ks2, +des_key_schedule ks3, +des_cblock *ivec, +int enc); + This function implements inner triple CBC DES encryption with 3 + keys. What this means is that each 'DES' operation + inside the cbc mode is really an C=E(ks3,D(ks2,E(ks1,M))). + Again, this is cbc mode so an ivec is requires. + This mode is used by SSL. + There is also a des_ede2_cbc_encrypt() that only uses 2 + des_key_schedule's, the first being reused for the final + encryption. C=E(ks1,D(ks2,E(ks1,M))). This form of triple DES + is used by the RSAref library. + +void des_pcbc_encrypt( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule ks, +des_cblock *ivec, +int enc); + This is Propagating Cipher Block Chaining mode of DES. It is used + by Kerberos v4. It's parameters are the same as des_ncbc_encrypt(). + +void des_cfb_encrypt( +unsigned char *in, +unsigned char *out, +int numbits, +long length, +des_key_schedule ks, +des_cblock *ivec, +int enc); + Cipher Feedback Back mode of DES. This implementation 'feeds back' + in numbit blocks. The input (and output) is in multiples of numbits + bits. numbits should to be a multiple of 8 bits. Length is the + number of bytes input. If numbits is not a multiple of 8 bits, + the extra bits in the bytes will be considered padding. So if + numbits is 12, for each 2 input bytes, the 4 high bits of the + second byte will be ignored. So to encode 72 bits when using + a numbits of 12 take 12 bytes. To encode 72 bits when using + numbits of 9 will take 16 bytes. To encode 80 bits when using + numbits of 16 will take 10 bytes. etc, etc. This padding will + apply to both input and output. + + +void des_cfb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks, +des_cblock *ivec, +int *num, +int enc); + This is one of the more useful functions in this DES library, it + implements CFB mode of DES with 64bit feedback. Why is this + useful you ask? Because this routine will allow you to encrypt an + arbitrary number of bytes, no 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. num contains 'how far' we are though ivec. If this does + not make much sense, read more about cfb mode of DES :-). + +void des_ede3_cfb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks1, +des_key_schedule ks2, +des_key_schedule ks3, +des_cblock *ivec, +int *num, +int enc); + Same as des_cfb64_encrypt() accept that the DES operation is + triple DES. As usual, there is a macro for + des_ede2_cfb64_encrypt() which reuses ks1. + +void des_ofb_encrypt( +unsigned char *in, +unsigned char *out, +int numbits, +long length, +des_key_schedule ks, +des_cblock *ivec); + This is a implementation of Output Feed Back mode of DES. It is + the same as des_cfb_encrypt() in that numbits is the size of the + units dealt with during input and output (in bits). + +void des_ofb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks, +des_cblock *ivec, +int *num); + The same as des_cfb64_encrypt() except that it is Output Feed Back + mode. + +void des_ede3_ofb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks1, +des_key_schedule ks2, +des_key_schedule ks3, +des_cblock *ivec, +int *num); + Same as des_ofb64_encrypt() accept that the DES operation is + triple DES. As usual, there is a macro for + des_ede2_ofb64_encrypt() which reuses ks1. + +int des_read_pw_string( +char *buf, +int length, +char *prompt, +int verify); + This routine is used to get a password from the terminal with echo + turned off. Buf is where the string will end up and length is the + size of buf. Prompt is a string presented to the 'user' and if + verify is set, the key is asked for twice and unless the 2 copies + match, an error is returned. A return code of -1 indicates a + system error, 1 failure due to use interaction, and 0 is success. + +unsigned long des_cbc_cksum( +des_cblock *input, +des_cblock *output, +long length, +des_key_schedule ks, +des_cblock *ivec); + This function produces an 8 byte checksum from input that it puts in + output and returns the last 4 bytes as a long. The checksum is + generated via cbc mode of DES in which only the last 8 byes are + kept. I would recommend not using this function but instead using + the EVP_Digest routines, or at least using MD5 or SHA. This + function is used by Kerberos v4 so that is why it stays in the + library. + +char *des_fcrypt( +const char *buf, +const char *salt +char *ret); + This is my fast version of the unix crypt(3) function. This version + takes only a small amount of space relative to other fast + crypt() implementations. This is different to the normal crypt + in that the third parameter is the buffer that the return value + is written into. It needs to be at least 14 bytes long. This + function is thread safe, unlike the normal crypt. + +char *crypt( +const char *buf, +const char *salt); + This function calls des_fcrypt() with a static array passed as the + third parameter. This emulates the normal non-thread safe semantics + of crypt(3). + +void des_string_to_key( +char *str, +des_cblock *key); + This function takes str and converts it into a DES key. I would + recommend using MD5 instead and use the first 8 bytes of output. + When I wrote the first version of these routines back in 1990, MD5 + did not exist but I feel these routines are still sound. This + routines is compatible with the one in MIT's libdes. + +void des_string_to_2keys( +char *str, +des_cblock *key1, +des_cblock *key2); + This function takes str and converts it into 2 DES keys. + I would recommend using MD5 and using the 16 bytes as the 2 keys. + I have nothing against these 2 'string_to_key' routines, it's just + that if you say that your encryption key is generated by using the + 16 bytes of an MD5 hash, every-one knows how you generated your + keys. + +int des_read_password( +des_cblock *key, +char *prompt, +int verify); + This routine combines des_read_pw_string() with des_string_to_key(). + +int des_read_2passwords( +des_cblock *key1, +des_cblock *key2, +char *prompt, +int verify); + This routine combines des_read_pw_string() with des_string_to_2key(). + +void des_random_seed( +des_cblock key); + This routine sets a starting point for des_random_key(). + +void des_random_key( +des_cblock ret); + This function return a random key. Make sure to 'seed' the random + number generator (with des_random_seed()) before using this function. + I personally now use a MD5 based random number system. + +int des_enc_read( +int fd, +char *buf, +int len, +des_key_schedule ks, +des_cblock *iv); + This function will write to a file descriptor the encrypted data + from buf. This data will be preceded by a 4 byte 'byte count' and + will be padded out to 8 bytes. The encryption is either CBC of + PCBC depending on the value of des_rw_mode. If it is DES_PCBC_MODE, + pcbc is used, if DES_CBC_MODE, cbc is used. The default is to use + DES_PCBC_MODE. + +int des_enc_write( +int fd, +char *buf, +int len, +des_key_schedule ks, +des_cblock *iv); + This routines read stuff written by des_enc_read() and decrypts it. + I have used these routines quite a lot but I don't believe they are + suitable for non-blocking io. If you are after a full + authentication/encryption over networks, have a look at SSL instead. + +unsigned long des_quad_cksum( +des_cblock *input, +des_cblock *output, +long length, +int out_count, +des_cblock *seed); + This is a function from Kerberos v4 that is not anything to do with + DES but was needed. It is a cksum that is quicker to generate than + des_cbc_cksum(); I personally would use MD5 routines now. +===== +Modes of DES +Quite a bit of the following information has been taken from + AS 2805.5.2 + Australian Standard + Electronic funds transfer - Requirements for interfaces, + Part 5.2: Modes of operation for an n-bit block cipher algorithm + Appendix A + +There are several different modes in which DES can be used, they are +as follows. + +Electronic Codebook Mode (ECB) (des_ecb_encrypt()) +- 64 bits are enciphered at a time. +- The order of the blocks can be rearranged without detection. +- The same plaintext block always produces the same ciphertext block + (for the same key) making it vulnerable to a 'dictionary attack'. +- An error will only affect one ciphertext block. + +Cipher Block Chaining Mode (CBC) (des_cbc_encrypt()) +- a multiple of 64 bits are enciphered at a time. +- The CBC mode produces the same ciphertext whenever the same + plaintext is encrypted using the same key and starting variable. +- The chaining operation makes the ciphertext blocks dependent on the + current and all preceding plaintext blocks and therefore blocks can not + be rearranged. +- The use of different starting variables prevents the same plaintext + enciphering to the same ciphertext. +- An error will affect the current and the following ciphertext blocks. + +Cipher Feedback Mode (CFB) (des_cfb_encrypt()) +- a number of bits (j) <= 64 are enciphered at a time. +- The CFB mode produces the same ciphertext whenever the same + plaintext is encrypted using the same key and starting variable. +- The chaining operation makes the ciphertext variables dependent on the + current and all preceding variables and therefore j-bit variables are + chained together and can not be rearranged. +- The use of different starting variables prevents the same plaintext + enciphering to the same ciphertext. +- The strength of the CFB mode depends on the size of k (maximal if + j == k). In my implementation this is always the case. +- Selection of a small value for j will require more cycles through + the encipherment algorithm per unit of plaintext and thus cause + greater processing overheads. +- Only multiples of j bits can be enciphered. +- An error will affect the current and the following ciphertext variables. + +Output Feedback Mode (OFB) (des_ofb_encrypt()) +- a number of bits (j) <= 64 are enciphered at a time. +- The OFB mode produces the same ciphertext whenever the same + plaintext enciphered using the same key and starting variable. More + over, in the OFB mode the same key stream is produced when the same + key and start variable are used. Consequently, for security reasons + a specific start variable should be used only once for a given key. +- The absence of chaining makes the OFB more vulnerable to specific attacks. +- The use of different start variables values prevents the same + plaintext enciphering to the same ciphertext, by producing different + key streams. +- Selection of a small value for j will require more cycles through + the encipherment algorithm per unit of plaintext and thus cause + greater processing overheads. +- Only multiples of j bits can be enciphered. +- OFB mode of operation does not extend ciphertext errors in the + resultant plaintext output. Every bit error in the ciphertext causes + only one bit to be in error in the deciphered plaintext. +- OFB mode is not self-synchronising. If the two operation of + encipherment and decipherment get out of synchronism, the system needs + to be re-initialised. +- Each re-initialisation should use a value of the start variable + different from the start variable values used before with the same + key. The reason for this is that an identical bit stream would be + produced each time from the same parameters. This would be + susceptible to a ' known plaintext' attack. + +Triple ECB Mode (des_ecb3_encrypt()) +- Encrypt with key1, decrypt with key2 and encrypt with key3 again. +- As for ECB encryption but increases the key length to 168 bits. + There are theoretic attacks that can be used that make the effective + key length 112 bits, but this attack also requires 2^56 blocks of + memory, not very likely, even for the NSA. +- If both keys are the same it is equivalent to encrypting once with + just one key. +- If the first and last key are the same, the key length is 112 bits. + There are attacks that could reduce the key space to 55 bit's but it + requires 2^56 blocks of memory. +- If all 3 keys are the same, this is effectively the same as normal + ecb mode. + +Triple CBC Mode (des_ede3_cbc_encrypt()) +- Encrypt with key1, decrypt with key2 and then encrypt with key3. +- As for CBC encryption but increases the key length to 168 bits with + the same restrictions as for triple ecb mode. diff --git a/doc/digest.doc b/doc/digest.doc new file mode 100644 index 0000000000..d2fb987591 --- /dev/null +++ b/doc/digest.doc @@ -0,0 +1,94 @@ + +The Message Digest subroutines. + +These routines require "evp.h" to be included. + +These functions are a higher level interface to the various message digest +routines found in this library. As such, they allow the same code to be +used to digest via different algorithms with only a change in an initial +parameter. They are basically just a front-end to the MD2, MD5, SHA +and SHA1 +routines. + +These routines all take a pointer to the following structure to specify +which message digest algorithm to use. +typedef struct evp_md_st + { + int type; + int pkey_type; + int md_size; + void (*init)(); + void (*update)(); + void (*final)(); + + int required_pkey_type; /*EVP_PKEY_xxx */ + int (*sign)(); + int (*verify)(); + } EVP_MD; + +If additional message digest algorithms are to be supported, a structure of +this type needs to be declared and populated and then the Digest routines +can be used with that algorithm. The type field is the object NID of the +digest type (read the section on Objects for an explanation). The pkey_type +is the Object type to use when the a message digest is generated by there +routines and then is to be signed with the pkey algorithm. Md_size is +the size of the message digest returned. Init, update +and final are the relevant functions to perform the message digest function +by parts. One reason for specifying the message digest to use via this +mechanism is that if you only use md5, only the md5 routines will +be included in you linked program. If you passed an integer +that specified which message digest to use, the routine that mapped that +integer to a set of message digest functions would cause all the message +digests functions to be link into the code. This setup also allows new +message digest functions to be added by the application. + +The six message digests defined in this library are + +EVP_MD *EVP_md2(void); /* RSA sign/verify */ +EVP_MD *EVP_md5(void); /* RSA sign/verify */ +EVP_MD *EVP_sha(void); /* RSA sign/verify */ +EVP_MD *EVP_sha1(void); /* RSA sign/verify */ +EVP_MD *EVP_dss(void); /* DSA sign/verify */ +EVP_MD *EVP_dss1(void); /* DSA sign/verify */ + +All the message digest routines take a EVP_MD_CTX pointer as an argument. +The state of the message digest is kept in this structure. + +typedef struct pem_md_ctx_st + { + EVP_MD *digest; + union { + unsigned char base[4]; /* this is used in my library as a + * 'pointer' to all union elements + * structures. */ + MD2_CTX md2; + MD5_CTX md5; + SHA_CTX sha; + } md; + } EVP_MD_CTX; + +The Digest functions are as follows. + +void EVP_DigestInit( +EVP_MD_CTX *ctx, +EVP_MD *type); + This function is used to initialise the EVP_MD_CTX. The message + digest that will associated with 'ctx' is specified by 'type'. + +void EVP_DigestUpdate( +EVP_MD_CTX *ctx, +unsigned char *data, +unsigned int cnt); + This function is used to pass more data to the message digest + function. 'cnt' bytes are digested from 'data'. + +void EVP_DigestFinal( +EVP_MD_CTX *ctx, +unsigned char *md, +unsigned int *len); + This function finishes the digestion and puts the message digest + into 'md'. The length of the message digest is put into len; + EVP_MAX_MD_SIZE is the size of the largest message digest that + can be returned from this function. Len can be NULL if the + size of the digest is not required. + diff --git a/doc/encode.doc b/doc/encode.doc new file mode 100644 index 0000000000..af17549289 --- /dev/null +++ b/doc/encode.doc @@ -0,0 +1,15 @@ + +void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); +void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out, + int *outl,unsigned char *in,int inl); +void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl); +int EVP_EncodeBlock(unsigned char *t, unsigned char *f, int n); + +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); +int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl, + unsigned char *in, int inl); +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned + char *out, int *outl); +int EVP_DecodeBlock(unsigned char *t, unsigned + char *f, int n); + diff --git a/doc/envelope.doc b/doc/envelope.doc new file mode 100644 index 0000000000..483e4fca6b --- /dev/null +++ b/doc/envelope.doc @@ -0,0 +1,67 @@ +The following routines are use to create 'digital' envelopes. +By this I mean that they perform various 'higher' level cryptographic +functions. Have a read of 'cipher.doc' and 'digest.doc' since those +routines are used by these functions. +cipher.doc contains documentation about the cipher part of the +envelope library and digest.doc contatins the description of the +message digests supported. + +To 'sign' a document involves generating a message digest and then encrypting +the digest with an private key. + +#define EVP_SignInit(a,b) EVP_DigestInit(a,b) +#define EVP_SignUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +Due to the fact this operation is basically just an extended message +digest, the first 2 functions are macro calls to Digest generating +functions. + +int EVP_SignFinal( +EVP_MD_CTX *ctx, +unsigned char *md, +unsigned int *s, +EVP_PKEY *pkey); + This finalisation function finishes the generation of the message +digest and then encrypts the digest (with the correct message digest +object identifier) with the EVP_PKEY private key. 'ctx' is the message digest +context. 'md' will end up containing the encrypted message digest. This +array needs to be EVP_PKEY_size(pkey) bytes long. 's' will actually +contain the exact length. 'pkey' of course is the private key. It is +one of EVP_PKEY_RSA or EVP_PKEY_DSA type. +If there is an error, 0 is returned, otherwise 1. + +Verify is used to check an signed message digest. + +#define EVP_VerifyInit(a,b) EVP_DigestInit(a,b) +#define EVP_VerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +Since the first step is to generate a message digest, the first 2 functions +are macros. + +int EVP_VerifyFinal( +EVP_MD_CTX *ctx, +unsigned char *md, +unsigned int s, +EVP_PKEY *pkey); + This function finishes the generation of the message digest and then +compares it with the supplied encrypted message digest. 'md' contains the +'s' bytes of encrypted message digest. 'pkey' is used to public key decrypt +the digest. It is then compared with the message digest just generated. +If they match, 1 is returned else 0. + +int EVP_SealInit(EVP_CIPHER_CTX *ctx, EVP_CIPHER *type, unsigned char **ek, + int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk); +Must have at least one public key, error is 0. I should also mention that +the buffers pointed to by 'ek' need to be EVP_PKEY_size(pubk[n]) is size. + +#define EVP_SealUpdate(a,b,c,d,e) EVP_EncryptUpdate(a,b,c,d,e) +void EVP_SealFinal(EVP_CIPHER_CTX *ctx,unsigned char *out,int *outl); + + +int EVP_OpenInit(EVP_CIPHER_CTX *ctx,EVP_CIPHER *type,unsigned char *ek, + int ekl,unsigned char *iv,EVP_PKEY *priv); +0 on failure + +#define EVP_OpenUpdate(a,b,c,d,e) EVP_DecryptUpdate(a,b,c,d,e) + +int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); +Decrypt final return code + diff --git a/doc/error.doc b/doc/error.doc new file mode 100644 index 0000000000..a91654999a --- /dev/null +++ b/doc/error.doc @@ -0,0 +1,115 @@ +The error routines. + +The 'error' system I've implemented is intended to server 2 purpose, to +record the reason why a command failed and to record where in the libraries +the failure occurred. It is more or less setup to record a 'trace' of which +library components were being traversed when the error occurred. + +When an error is recorded, it is done so a as single unsigned long which is +composed of three parts. The top byte is the 'library' number, the middle +12 bytes is the function code, and the bottom 12 bits is the 'reason' code. + +Each 'library', or should a say, 'section' of the SSLeay library has a +different unique 'library' error number. Each function in the library has +a number that is unique for that library. Each 'library' also has a number +for each 'error reason' that is only unique for that 'library'. + +Due to the way these error routines record a 'error trace', there is an +array per thread that is used to store the error codes. +The various functions in this library are used to access +and manipulate this array. + +void ERR_put_error(int lib, int func,int reason); + This routine records an error in library 'lib', function 'func' +and reason 'reason'. As errors get 'put' into the buffer, they wrap +around and overwrite old errors if too many are written. It is assumed +that the last errors are the most important. + +unsigned long ERR_get_error(void ); + This function returns the last error added to the error buffer. +In effect it is popping the value off the buffer so repeated calls will +continue to return values until there are no more errors to return in which +case 0 is returned. + +unsigned long ERR_peek_error(void ); + This function returns the value of the last error added to the +error buffer but does not 'pop' it from the buffer. + +void ERR_clear_error(void ); + This function clears the error buffer, discarding all unread +errors. + +While the above described error system obviously produces lots of different +error number, a method for 'reporting' these errors in a human readable +form is required. To achieve this, each library has the option of +'registering' error strings. + +typedef struct ERR_string_data_st + { + unsigned long error; + char *string; + } ERR_STRING_DATA; + +The 'ERR_STRING_DATA' contains an error code and the corresponding text +string. To add new function error strings for a library, the +ERR_STRING_DATA needs to be 'registered' with the library. + +void ERR_load_strings(unsigned long lib,ERR_STRING_DATA *err); + This function 'registers' the array of ERR_STRING_DATA pointed to by +'err' as error text strings for the error library 'lib'. + +void ERR_free_strings(void); + This function free()s all the loaded error strings. + +char *ERR_error_string(unsigned long error,char *buf); + This function returns a text string that is a human readable +version of the error represented by 'error'. Buff should be at least 120 +bytes long and if it is NULL, the return value is a pointer to a static +variable that will contain the error string, otherwise 'buf' is returned. +If there is not a text string registered for a particular error, a text +string containing the error number is returned instead. + +void ERR_print_errors(BIO *bp); +void ERR_print_errors_fp(FILE *fp); + This function is a convenience routine that prints the error string +for each error until all errors have been accounted for. + +char *ERR_lib_error_string(unsigned long e); +char *ERR_func_error_string(unsigned long e); +char *ERR_reason_error_string(unsigned long e); +The above three functions return the 3 different components strings for the +error 'e'. ERR_error_string() uses these functions. + +void ERR_load_ERR_strings(void ); + This function 'registers' the error strings for the 'ERR' module. + +void ERR_load_crypto_strings(void ); + This function 'register' the error strings for just about every +library in the SSLeay package except for the SSL routines. There is no +need to ever register any error text strings and you will probably save in +program size. If on the other hand you do 'register' all errors, it is +quite easy to determine why a particular routine failed. + +As a final footnote as to why the error system is designed as it is. +1) I did not want a single 'global' error code. +2) I wanted to know which subroutine a failure occurred in. +3) For Windows NT etc, it should be simple to replace the 'key' routines + with code to pass error codes back to the application. +4) I wanted the option of meaningful error text strings. + +Late breaking news - the changes to support threads. + +Each 'thread' has an 'ERR_STATE' state associated with it. +ERR_STATE *ERR_get_state(void ) will return the 'state' for the calling +thread/process. + +ERR_remove_state(unsigned long pid); will 'free()' this state. If pid == 0 +the current 'thread/process' will have it's error state removed. +If you do not remove the error state of a thread, this could be considered a +form of memory leak, so just after 'reaping' a thread that has died, +call ERR_remove_state(pid). + +Have a read of thread.doc for more details for what is required for +multi-threading support. All the other error routines will +work correctly when using threads. + diff --git a/doc/idea.doc b/doc/idea.doc new file mode 100644 index 0000000000..68a22a6cae --- /dev/null +++ b/doc/idea.doc @@ -0,0 +1,176 @@ +The IDEA library. +IDEA is a block cipher that operates on 64bit (8 byte) quantities. It +uses a 128bit (16 byte) key. It can be used in all the modes that DES can +be used. This library implements the ecb, cbc, cfb64 and ofb64 modes. + +For all calls that have an 'input' and 'output' variables, they can be the +same. + +This library requires the inclusion of 'idea.h'. + +All of the encryption functions take what is called an IDEA_KEY_SCHEDULE as an +argument. An IDEA_KEY_SCHEDULE is an expanded form of the idea key. +For all modes of the IDEA algorithm, the IDEA_KEY_SCHEDULE used for +decryption is different to the one used for encryption. + +The define IDEA_ENCRYPT is passed to specify encryption for the functions +that require an encryption/decryption flag. IDEA_DECRYPT is passed to +specify decryption. For some mode there is no encryption/decryption +flag since this is determined by the IDEA_KEY_SCHEDULE. + +So to encrypt you would do the following +idea_set_encrypt_key(key,encrypt_ks); +idea_ecb_encrypt(...,encrypt_ks); +idea_cbc_encrypt(....,encrypt_ks,...,IDEA_ENCRYPT); + +To Decrypt +idea_set_encrypt_key(key,encrypt_ks); +idea_set_decrypt_key(encrypt_ks,decrypt_ks); +idea_ecb_encrypt(...,decrypt_ks); +idea_cbc_encrypt(....,decrypt_ks,...,IDEA_DECRYPT); + +Please note that any of the encryption modes specified in my DES library +could be used with IDEA. I have only implemented ecb, cbc, cfb64 and +ofb64 for the following reasons. +- ecb is the basic IDEA encryption. +- cbc is the normal 'chaining' form for block ciphers. +- cfb64 can be used to encrypt single characters, therefore input and output + do not need to be a multiple of 8. +- ofb64 is similar to cfb64 but is more like a stream cipher, not as + secure (not cipher feedback) but it does not have an encrypt/decrypt mode. +- If you want triple IDEA, thats 384 bits of key and you must be totally + obsessed with security. Still, if you want it, it is simple enough to + copy the function from the DES library and change the des_encrypt to + idea_encrypt; an exercise left for the paranoid reader :-). + +The functions are as follows: + +void idea_set_encrypt_key( +unsigned char *key; +IDEA_KEY_SCHEDULE *ks); + idea_set_encrypt_key converts a 16 byte IDEA key into an + IDEA_KEY_SCHEDULE. The IDEA_KEY_SCHEDULE is an expanded form of + the key which can be used to perform IDEA encryption. + An IDEA_KEY_SCHEDULE is an expanded form of the key which is used to + perform actual encryption. It can be regenerated from the IDEA key + so it only needs to be kept when encryption is about + to occur. Don't save or pass around IDEA_KEY_SCHEDULE's since they + are CPU architecture dependent, IDEA keys are not. + +void idea_set_decrypt_key( +IDEA_KEY_SCHEDULE *encrypt_ks, +IDEA_KEY_SCHEDULE *decrypt_ks); + This functions converts an encryption IDEA_KEY_SCHEDULE into a + decryption IDEA_KEY_SCHEDULE. For all decryption, this conversion + of the key must be done. In some modes of IDEA, an + encryption/decryption flag is also required, this is because these + functions involve block chaining and the way this is done changes + depending on which of encryption of decryption is being done. + Please note that there is no quick way to generate the decryption + key schedule other than generating the encryption key schedule and + then converting it. + +void idea_encrypt( +unsigned long *data, +IDEA_KEY_SCHEDULE *ks); + This is the IDEA encryption function that gets called by just about + every other IDEA routine in the library. You should not use this + function except to implement 'modes' of IDEA. I say this because the + functions that call this routine do the conversion from 'char *' to + long, and this needs to be done to make sure 'non-aligned' memory + access do not occur. + Data is a pointer to 2 unsigned long's and ks is the + IDEA_KEY_SCHEDULE to use. Encryption or decryption depends on the + IDEA_KEY_SCHEDULE. + +void idea_ecb_encrypt( +unsigned char *input, +unsigned char *output, +IDEA_KEY_SCHEDULE *ks); + This is the basic Electronic Code Book form of IDEA (in DES this + mode is called Electronic Code Book so I'm going to use the term + for idea as well :-). + Input is encrypted into output using the key represented by + ks. Depending on the IDEA_KEY_SCHEDULE, encryption or + decryption occurs. Input is 8 bytes long and output is 8 bytes. + +void idea_cbc_encrypt( +unsigned char *input, +unsigned char *output, +long length, +IDEA_KEY_SCHEDULE *ks, +unsigned char *ivec, +int enc); + This routine implements IDEA in Cipher Block Chaining mode. + Input, which should be a multiple of 8 bytes is encrypted + (or decrypted) to output which will also be a multiple of 8 bytes. + The number of bytes is in length (and from what I've said above, + should be a multiple of 8). If length is not a multiple of 8, bad + things will probably happen. ivec is the initialisation vector. + This function updates iv after each call so that it can be passed to + the next call to idea_cbc_encrypt(). + +void idea_cfb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks, +des_cblock *ivec, +int *num, +int enc); + This is one of the more useful functions in this IDEA library, it + implements CFB mode of IDEA with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + Enc is used to indicate encryption or decryption. + One very important thing to remember is that when decrypting, use + the encryption form of the key. + CFB64 mode operates by using the cipher to + generate a stream of bytes which is used to encrypt the plain text. + The cipher text is then encrypted to generate the next 64 bits to + be xored (incrementally) with the next 64 bits of plain + text. As can be seen from this, to encrypt or decrypt, + the same 'cipher stream' needs to be generated but the way the next + block of data is gathered for encryption is different for + encryption and decryption. What this means is that to encrypt + idea_set_encrypt_key(key,ks); + idea_cfb64_encrypt(...,ks,..,IDEA_ENCRYPT) + do decrypt + idea_set_encrypt_key(key,ks) + idea_cfb64_encrypt(...,ks,...,IDEA_DECRYPT) + Note: The same IDEA_KEY_SCHEDULE but different encryption flags. + For idea_cbc or idea_ecb, idea_set_decrypt_key() would need to be + used to generate the IDEA_KEY_SCHEDULE for decryption. + The reason I'm stressing this point is that I just wasted 3 hours + today trying to decrypt using this mode and the decryption form of + the key :-(. + +void idea_ofb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +des_key_schedule ks, +des_cblock *ivec, +int *num); + This functions implements OFB mode of IDEA with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + This is in effect a stream cipher, there is no encryption or + decryption mode. The same key and iv should be used to + encrypt and decrypt. + +For reading passwords, I suggest using des_read_pw_string() from my DES library. +To generate a password from a text string, I suggest using MD5 (or MD2) to +produce a 16 byte message digest that can then be passed directly to +idea_set_encrypt_key(). + +===== +For more information about the specific IDEA modes in this library +(ecb, cbc, cfb and ofb), read the section entitled 'Modes of DES' from the +documentation on my DES library. What is said about DES is directly +applicable for IDEA. + diff --git a/doc/legal.doc b/doc/legal.doc new file mode 100644 index 0000000000..b55ed5ce6a --- /dev/null +++ b/doc/legal.doc @@ -0,0 +1,117 @@ +From eay@mincom.com Thu Jun 27 00:25:45 1996 +Received: by orb.mincom.oz.au id AA15821 + (5.65c/IDA-1.4.4 for eay); Wed, 26 Jun 1996 14:25:45 +1000 +Date: Wed, 26 Jun 1996 14:25:45 +1000 (EST) +From: Eric Young <eay@mincom.oz.au> +X-Sender: eay@orb +To: Ken Toll <ktoll@ren.digitalage.com> +Cc: Eric Young <eay@mincom.oz.au>, ssl-talk@netscape.com +Subject: Re: Unidentified subject! +In-Reply-To: <9606261950.ZM28943@ren.digitalage.com> +Message-Id: <Pine.SOL.3.91.960626131156.28573K-100000@orb> +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Status: O +X-Status: + + +This is a little off topic but since SSLeay is a free implementation of +the SSLv2 protocol, I feel it is worth responding on the topic of if it +is actually legal for Americans to use free cryptographic software. + +On Wed, 26 Jun 1996, Ken Toll wrote: +> Is the U.S the only country that SSLeay cannot be used commercially +> (because of RSAref) or is that going to be an issue with every country +> that a client/server application (non-web browser/server) is deployed +> and sold? + +>From what I understand, the software patents that apply to algorithms +like RSA and DH only apply in the USA. The IDEA algorithm I believe is +patened in europe (USA?), but considing how little it is used by other SSL +implementations, it quite easily be left out of the SSLeay build +(this can be done with a compile flag). + +Actually if the RSA patent did apply outside the USA, it could be rather +interesting since RSA is not alowed to let RSA toolkits outside of the USA +[1], and since these are the only forms that they will alow the algorithm +to be used in, it would mean that non-one outside of the USA could produce +public key software which would be a very strong statment for +international patent law to make :-). This logic is a little flawed but +it still points out some of the more interesting permutations of USA +patent law and ITAR restrictions. + +Inside the USA there is also the unresolved issue of RC4/RC2 which were +made public on sci.crypt in Sep 1994 (RC4) and Feb 1996 (RC2). I have +copies of the origional postings if people are interested. RSA I believe +claim that they were 'trade-secrets' and that some-one broke an NDA in +revealing them. Other claim they reverse engineered the algorithms from +compiled binaries. If the algorithms were reverse engineered, I belive +RSA had no legal leg to stand on. If an NDA was broken, I don't know. +Regardless, RSA, I belive, is willing to go to court over the issue so +licencing is probably the best idea, or at least talk to them. +If there are people who actually know more about this, pease let me know, I +don't want to vilify or spread miss-information if I can help it. + +If you are not producing a web browser, it is easy to build SSLeay with +RC2/RC4 removed. Since RC4 is the defacto standard cipher in +all web software (and it is damn fast) it is more or less required for +www use. For non www use of SSL, especially for an application where +interoperability with other vendors is not critical just leave it out. + +Removing IDEA, RC2 and RC4 would only leave DES and Triple DES but +they should be ok. Considing that Triple DES can encrypt at rates of +410k/sec on a pentium 100, and 940k/sec on a P6/200, this is quite +reasonable performance. Single DES clocks in at 1160k/s and 2467k/s +respectivly is actually quite fast for those not so paranoid (56 bit key).[1] + +> Is it possible to get a certificate for commercial use outside of the U.S.? +yes. + +Thawte Consulting issues certificates (they are the people who sell the + Sioux httpd server and are based in South Africa) +Verisign will issue certificates for Sioux (sold from South Africa), so this + proves that they will issue certificate for OS use if they are + happy with the quality of the software. + +(The above mentioned companies just the ones that I know for sure are issuing + certificates outside the USA). + +There is always the point that if you are using SSL for an intra net, +SSLeay provides programs that can be used so you can issue your own +certificates. They need polishing but at least it is a good starting point. + +I am not doing anything outside Australian law by implementing these +algorithms (to the best of my knowedge). It is another example of how +the world legal system does not cope with the internet very well. + +I may start making shared libraries available (I have now got DLL's for +Windows). This will mean that distributions into the usa could be +shipped with a version with a reduced cipher set and the versions outside +could use the DLL/shared library with all the ciphers (and without RSAref). + +This could be completly hidden from the application, so this would not +even require a re-linking. + +This is the reverse of what people were talking about doing to get around +USA export regulations :-) + +eric + +[1]: The RSAref2.0 tookit is available on at least 3 ftp sites in Europe + and one in South Africa. + +[2]: Since I always get questions when I post benchmark numbers :-), + DES performace figures are in 1000's of bytes per second in cbc + mode using an 8192 byte buffer. The pentium 100 was running Windows NT + 3.51 DLLs and the 686/200 was running NextStep. + I quote pentium 100 benchmarks because it is basically the + 'entry level' computer that most people buy for personal use. + Windows 95 is the OS shipping on those boxes, so I'll give + NT numbers (the same Win32 runtime environment). The 686 + numbers are present as an indication of where we will be in a + few years. +-- +Eric Young | BOOL is tri-state according to Bill Gates. +AARNet: eay@mincom.oz.au | RTFM Win32 GetMessage(). + + diff --git a/doc/lhash.doc b/doc/lhash.doc new file mode 100644 index 0000000000..5a2aeb4b38 --- /dev/null +++ b/doc/lhash.doc @@ -0,0 +1,151 @@ +The LHASH library. + +I wrote this library in 1991 and have since forgotten why I called it lhash. +It implements a hash table from an article I read at the +time from 'Communications of the ACM'. What makes this hash +table different is that as the table fills, the hash table is +increased (or decreased) in size via realloc(). +When a 'resize' is done, instead of all hashes being redistributed over +twice as many 'buckets', one bucket is split. So when an 'expand' is done, +there is only a minimal cost to redistribute some values. Subsequent +inserts will cause more single 'bucket' redistributions but there will +never be a sudden large cost due to redistributing all the 'buckets'. + +The state for a particular hash table is kept in the LHASH structure. +The LHASH structure also records statistics about most aspects of accessing +the hash table. This is mostly a legacy of my writing this library for +the reasons of implementing what looked like a nice algorithm rather than +for a particular software product. + +Internal stuff you probably don't want to know about. +The decision to increase or decrease the hash table size is made depending +on the 'load' of the hash table. The load is the number of items in the +hash table divided by the size of the hash table. The default values are +as follows. If (hash->up_load < load) => expand. +if (hash->down_load > load) => contract. The 'up_load' has a default value of +1 and 'down_load' has a default value of 2. These numbers can be modified +by the application by just playing with the 'up_load' and 'down_load' +variables. The 'load' is kept in a form which is multiplied by 256. So +hash->up_load=8*256; will cause a load of 8 to be set. + +If you are interested in performance the field to watch is +num_comp_calls. The hash library keeps track of the 'hash' value for +each item so when a lookup is done, the 'hashes' are compared, if +there is a match, then a full compare is done, and +hash->num_comp_calls is incremented. If num_comp_calls is not equal +to num_delete plus num_retrieve it means that your hash function is +generating hashes that are the same for different values. It is +probably worth changing your hash function if this is the case because +even if your hash table has 10 items in a 'bucked', it can be searched +with 10 'unsigned long' compares and 10 linked list traverses. This +will be much less expensive that 10 calls to you compare function. + +LHASH *lh_new( +unsigned long (*hash)(), +int (*cmp)()); + This function is used to create a new LHASH structure. It is passed + function pointers that are used to store and retrieve values passed + into the hash table. The 'hash' + function is a hashing function that will return a hashed value of + it's passed structure. 'cmp' is passed 2 parameters, it returns 0 + is they are equal, otherwise, non zero. + If there are any problems (usually malloc failures), NULL is + returned, otherwise a new LHASH structure is returned. The + hash value is normally truncated to a power of 2, so make sure + that your hash function returns well mixed low order bits. + +void lh_free( +LHASH *lh); + This function free()s a LHASH structure. If there is malloced + data in the hash table, it will not be freed. Consider using the + lh_doall function to deallocate any remaining entries in the hash + table. + +char *lh_insert( +LHASH *lh, +char *data); + This function inserts the data pointed to by data into the lh hash + table. If there is already and entry in the hash table entry, the + value being replaced is returned. A NULL is returned if the new + entry does not clash with an entry already in the table (the normal + case) or on a malloc() failure (perhaps I should change this....). + The 'char *data' is exactly what is passed to the hash and + comparison functions specified in lh_new(). + +char *lh_delete( +LHASH *lh, +char *data); + This routine deletes an entry from the hash table. The value being + deleted is returned. NULL is returned if there is no such value in + the hash table. + +char *lh_retrieve( +LHASH *lh, +char *data); + If 'data' is in the hash table it is returned, else NULL is + returned. The way these routines would normally be uses is that a + dummy structure would have key fields populated and then + ret=lh_retrieve(hash,&dummy);. Ret would now be a pointer to a fully + populated structure. + +void lh_doall( +LHASH *lh, +void (*func)(char *a)); + This function will, for every entry in the hash table, call function + 'func' with the data item as parameters. + This function can be quite useful when used as follows. + void cleanup(STUFF *a) + { STUFF_free(a); } + lh_doall(hash,cleanup); + lh_free(hash); + This can be used to free all the entries, lh_free() then + cleans up the 'buckets' that point to nothing. Be careful + when doing this. If you delete entries from the hash table, + in the call back function, the table may decrease in size, + moving item that you are + currently on down lower in the hash table. This could cause + some entries to be skipped. The best solution to this problem + is to set lh->down_load=0 before you start. This will stop + the hash table ever being decreased in size. + +void lh_doall_arg( +LHASH *lh; +void(*func)(char *a,char *arg)); +char *arg; + This function is the same as lh_doall except that the function + called will be passed 'arg' as the second argument. + +unsigned long lh_strhash( +char *c); + This function is a demo string hashing function. Since the LHASH + routines would normally be passed structures, this routine would + not normally be passed to lh_new(), rather it would be used in the + function passed to lh_new(). + +The next three routines print out various statistics about the state of the +passed hash table. These numbers are all kept in the lhash structure. + +void lh_stats( +LHASH *lh, +FILE *out); + This function prints out statistics on the size of the hash table, + how many entries are in it, and the number and result of calls to + the routines in this library. + +void lh_node_stats( +LHASH *lh, +FILE *out); + For each 'bucket' in the hash table, the number of entries is + printed. + +void lh_node_usage_stats( +LHASH *lh, +FILE *out); + This function prints out a short summary of the state of the hash + table. It prints what I call the 'load' and the 'actual load'. + The load is the average number of data items per 'bucket' in the + hash table. The 'actual load' is the average number of items per + 'bucket', but only for buckets which contain entries. So the + 'actual load' is the average number of searches that will need to + find an item in the hash table, while the 'load' is the average number + that will be done to record a miss. diff --git a/doc/md2.doc b/doc/md2.doc new file mode 100644 index 0000000000..b106bc675d --- /dev/null +++ b/doc/md2.doc @@ -0,0 +1,49 @@ +The MD2 library. +MD2 is a message digest algorithm that can be used to condense an arbitrary +length message down to a 16 byte hash. The functions all need to be passed +a MD2_CTX which is used to hold the MD2 context during multiple MD2_Update() +function calls. The normal method of use for this library is as follows + +MD2_Init(...); +MD2_Update(...); +... +MD2_Update(...); +MD2_Final(...); + +This library requires the inclusion of 'md2.h'. + +The main negative about MD2 is that it is slow, especially when compared +to MD5. + +The functions are as follows: + +void MD2_Init( +MD2_CTX *c); + This function needs to be called to initiate a MD2_CTX structure for + use. + +void MD2_Update( +MD2_CTX *c; +unsigned char *data; +unsigned long len); + This updates the message digest context being generated with 'len' + bytes from the 'data' pointer. The number of bytes can be any + length. + +void MD2_Final( +unsigned char *md; +MD2_CTX *c; + This function is called when a message digest of the data digested + with MD2_Update() is wanted. The message digest is put in the 'md' + array and is MD2_DIGEST_LENGTH (16) bytes long. + +unsigned char *MD2( +unsigned long n; +unsigned char *d; +unsigned char *md; + This function performs a MD2_Init(), followed by a MD2_Update() + followed by a MD2_Final() (using a local MD2_CTX). + The resulting digest is put into 'md' if it is not NULL. + Regardless of the value of 'md', the message + digest is returned from the function. If 'md' was NULL, the message + digest returned is being stored in a static structure. diff --git a/doc/md5.doc b/doc/md5.doc new file mode 100644 index 0000000000..519dbdc61a --- /dev/null +++ b/doc/md5.doc @@ -0,0 +1,50 @@ +The MD5 library. +MD5 is a message digest algorithm that can be used to condense an arbitrary +length message down to a 16 byte hash. The functions all need to be passed +a MD5_CTX which is used to hold the MD5 context during multiple MD5_Update() +function calls. This library also contains random number routines that are +based on MD5 + +The normal method of use for this library is as follows + +MD5_Init(...); +MD5_Update(...); +... +MD5_Update(...); +MD5_Final(...); + +This library requires the inclusion of 'md5.h'. + +The functions are as follows: + +void MD5_Init( +MD5_CTX *c); + This function needs to be called to initiate a MD5_CTX structure for + use. + +void MD5_Update( +MD5_CTX *c; +unsigned char *data; +unsigned long len); + This updates the message digest context being generated with 'len' + bytes from the 'data' pointer. The number of bytes can be any + length. + +void MD5_Final( +unsigned char *md; +MD5_CTX *c; + This function is called when a message digest of the data digested + with MD5_Update() is wanted. The message digest is put in the 'md' + array and is MD5_DIGEST_LENGTH (16) bytes long. + +unsigned char *MD5( +unsigned char *d; +unsigned long n; +unsigned char *md; + This function performs a MD5_Init(), followed by a MD5_Update() + followed by a MD5_Final() (using a local MD5_CTX). + The resulting digest is put into 'md' if it is not NULL. + Regardless of the value of 'md', the message + digest is returned from the function. If 'md' was NULL, the message + digest returned is being stored in a static structure. + diff --git a/doc/memory.doc b/doc/memory.doc new file mode 100644 index 0000000000..b9aa33ace0 --- /dev/null +++ b/doc/memory.doc @@ -0,0 +1,27 @@ +In the interests of debugging SSLeay, there is an option to compile +using some simple memory leak checking. + +All malloc(), free() and realloc() calls in SSLeay now go via +Malloc(), Free() and Realloc() (except those in crypto/lhash). + +If CRYPTO_MDEBUG is defined, these calls are #defined to +CRYPTO_malloc(), CRYPTO_free() and CRYPTO_realloc(). +If it is not defined, they are #defined to malloc(), free() and realloc(). + +the CRYPTO_malloc() routines by default just call the underlying library +functons. + +If CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON) is called, memory leak detection is +turned on. CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF) turns it off. + +When turned on, each Malloc() or Realloc() call is recored along with the file +and line number from where the call was made. (This is done using the +lhash library which always uses normal system malloc(3) routines). + +void CRYPTO_mem_leaks(BIO *b); +void CRYPTO_mem_leaks_fp(FILE *fp); +These both print out the list of memory that has not been free()ed. +This will probably be rather hard to read, but if you look for the 'top level' +structure allocation, this will often give an idea as to what is not being +free()ed. I don't expect people to use this stuff normally. + diff --git a/doc/ms3-ca.doc b/doc/ms3-ca.doc new file mode 100644 index 0000000000..f8350aadc2 --- /dev/null +++ b/doc/ms3-ca.doc @@ -0,0 +1,398 @@ +Date: Mon, 9 Jun 97 08:00:33 +0200 +From: Holger.Reif@PrakInf.TU-Ilmenau.DE (Holger Reif) +Subject: ms3-ca.doc +Organization: TU Ilmenau, Fak. IA, FG Telematik +Content-Length: 14575 +Status: RO +X-Status: + +Loading client certs into MSIE 3.01 +=================================== + +This document conatains all the information necessary to succesfully set up +some scripts to issue client certs to Microsoft Internet Explorer. It +includes the required knowledge about the model MSIE uses for client +certification and includes complete sample scripts ready to play with. The +scripts were tested against a modified ca program of SSLeay 0.6.6 and should +work with the regular ca program that comes with version 0.8.0. I haven't +tested against MSIE 4.0 + +You can use the information contained in this document in either way you +want. However if you feel it saved you a lot of time I ask you to be as fair +as to mention my name: Holger Reif <reif@prakinf.tu-ilmenau.de>. + +1.) The model used by MSIE +-------------------------- + +The Internet Explorer doesn't come with a embedded engine for installing +client certs like Netscape's Navigator. It rather uses the CryptoAPI (CAPI) +defined by Microsoft. CAPI comes with WindowsNT 4.0 or is installed together +with Internet Explorer since 3.01. The advantage of this approach is a higher +flexibility because the certificates in the (per user) system open +certificate store may be used by other applications as well. The drawback +however is that you need to do a bit more work to get a client cert issued. + +CAPI defines functions which will handle basic cryptographic work, eg. +generating keys, encrypting some data, signing text or building a certificate +request. The procedure is as follows: A CAPI function generates you a key +pair and saves it into the certificate store. After that one builds a +Distinguished Name. Together with that key pair another CAPI function forms a +PKCS#10 request which you somehow need to submit to a CA. Finally the issued +cert is given to a yet another CAPI function which saves it into the +certificate store. + +The certificate store with the user's keys and certs is in the registry. You +will find it under HKEY_CURRENT_USER/Software/Microsoft/Cryptography/ (I +leave it to you as a little exercise to figure out what all the entries mean +;-). Note that the keys are protected only with the user's usual Windows +login password. + +2.) The practical usage +----------------------- + +Unfortunatly since CAPI is a system API you can't access its functions from +HTML code directly. For this purpose Microsoft provides a wrapper called +certenr3.dll. This DLL accesses the CAPI functions and provides an interface +usable from Visual Basic Script. One needs to install that library on the +computer which wants to have client cert. The easiest way is to load it as an +ActiveX control (certenr3.dll is properly authenticode signed by MS ;-). If +you have ever enrolled e cert request at a CA you will have installed it. + +At time of writing certenr3.dll is contained in +http://www.microsoft.com/workshop/prog/security/csa/certenr3.exe. It comes +with an README file which explains the available functions. It is labeled +beta but every CA seems to use it anyway. The license.txt allows you the +usage for your own purposes (as far as I understood) and a somehow limited +distribution. + +The two functions of main interest are GenerateKeyPair and AcceptCredentials. +For complete explanation of all possible parameters see the README file. Here +are only minimal required parameters and their values. + +GenerateKeyPair(sessionID, FASLE, szName, 0, "ClientAuth", TRUE, FALSE, 1) +- sessionID is a (locally to that computer) unique string to correlate the +generated key pair with a cert installed later. +- szName is the DN of the form "C=DE; S=Thueringen; L=Ilmenau; CN=Holger +Reif; 1.2.840.113549.1.9.1=reif@prakinf.tu-ilmenau.de". Note that S is the +abreviation for StateOrProvince. The recognized abreviation include CN, O, C, +OU, G, I, L, S, T. If the abreviation is unknown (eg. for PKCS#9 email addr) +you need to use the full object identifier. The starting point for searching +them could be crypto/objects.h since all OIDs know to SSLeay are listed +there. +- note: the possible ninth parameter which should give a default name to the +certificate storage location doesn't seem to work. Changes to the constant +values in the call above doesn't seem to make sense. You can't generate +PKCS#10 extensions with that function. + +The result of GenerateKeyPair is the base64 encoded PKCS#10 request. However +it has a little strange format that SSLeay doesn't accept. (BTW I feel the +decision of rejecting that format as standard conforming.) It looks like +follows: + 1st line with 76 chars + 2nd line with 76 chars + ... + (n-2)th line with 76 chars + (n-1)th line contains a multiple of 4 chars less then 76 (possible +empty) + (n)th line has zero or 4 chars (then with 1 or 2 equal signs - the + original text's lenght wasn'T a multiple of 3) + The line separator has two chars: 0x0d 0x0a + +AcceptCredentials(sessionID, credentials, 0, FALSE) +- sessionID needs to be the same as while generating the key pair +- credentials is the base64 encoded PKCS#7 object containing the cert. + +CRL's and CA certs are not required simply just the client cert. (It seems to +me that both are not even checked somehow.) The only format of the base64 +encoded object I succesfully used was all characters in a very long string +without line feeds or carriage returns. (Hey, it doesn't matter, only a +computer reads it!) + +The result should be S_OK. For error handling see the example that comes with +certenr3.dll. + +A note about ASN.1 character encodings. certenr3.dll seems to know only about +2 of them: UniversalString and PrintableString. First it is definitely wrong +for an email address which is IA5STRING (checked by ssleay's ca). Second +unfortunately MSIE (at least until version 3.02) can't handle UniversalString +correctly - they just blow up you cert store! Therefore ssleay's ca (starting +from version 0.8.0) tries to convert the encodings automatically to IA5STRING +or TeletexString. The beef is it will work only for the latin-1 (western) +charset. Microsoft still has to do abit of homework... + +3.) An example +-------------- + +At least you need two steps: generating the key & request and then installing +the certificate. A real world CA would have some more steps involved, eg. +accepting some license. Note that both scripts shown below are just +experimental state without any warrenty! + +First how to generate a request. Note that we can't use a static page because +of the sessionID. I generate it from system time plus pid and hope it is +unique enough. Your are free to feed it through md5 to get more impressive +ID's ;-) Then the intended text is read in with sed which inserts the +sessionID. + +-----BEGIN ms-enroll.cgi----- +#!/bin/sh +SESSION_ID=`date '+%y%m%d%H%M%S'`$$ +echo Content-type: text/html +echo +sed s/template_for_sessId/$SESSION_ID/ <<EOF +<HTML><HEAD> +<TITLE>Certificate Enrollment Test Page</TITLE> +</HEAD><BODY> + +<OBJECT + classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" + codebase=certenr3.dll + id=certHelper + > +</OBJECT> + +<CENTER> +<H2>enrollment for a personal cert</H2> +<BR><HR WIDTH=50%><BR><P> +<FORM NAME="MSIE_Enrollment" ACTION="ms-gencert.cgi" ENCTYPE=x-www-form- +encoded METHOD=POST> +<TABLE> + <TR><TD>Country</TD><TD><INPUT NAME="Country" VALUE=""></TD></TR> + <TR><TD>State</TD><TD><INPUT NAME="StateOrProvince" VALUE=""></TD></TR> + <TR><TD>Location</TD><TD><INPUT NAME="Location" VALUE=""></TD></TR> + <TR><TD>Organization</TD><TD><INPUT NAME="Organization" +VALUE=""></TD></TR> + <TR><TD>Organizational Unit</TD> + <TD><INPUT NAME="OrganizationalUnit" VALUE=""></TD></TR> + <TR><TD>Name</TD><TD><INPUT NAME="CommonName" VALUE=""></TD></TR> + <TR><TD>eMail Address</TD> + <TD><INPUT NAME="EmailAddress" VALUE=""></TD></TR> + <TR><TD></TD> + <TD><INPUT TYPE="BUTTON" NAME="submit" VALUE="Beantragen"></TD></TR> +</TABLE> + <INPUT TYPE="hidden" NAME="SessionId" VALUE="template_for_sessId"> + <INPUT TYPE="hidden" NAME="Request" VALUE=""> +</FORM> +<BR><HR WIDTH=50%><BR><P> +</CENTER> + +<SCRIPT LANGUAGE=VBS> + Dim DN + + Sub Submit_OnClick + Dim TheForm + Set TheForm = Document.MSIE_Enrollment + sessionId = TheForm.SessionId.value + reqHardware = FALSE + C = TheForm.Country.value + SP = TheForm.StateOrProvince.value + L = TheForm.Location.value + O = TheForm.Organization.value + OU = TheForm.OrganizationalUnit.value + CN = TheForm.CommonName.value + Email = TheForm.EmailAddress.value + szPurpose = "ClientAuth" + doAcceptanceUINow = FALSE + doOnline = TRUE + + DN = "" + + Call Add_RDN("C", C) + Call Add_RDN("S", SP) + Call Add_RDN("L", L) + Call Add_RDN("O", O) + Call Add_RDN("OU", OU) + Call Add_RDN("CN", CN) + Call Add_RDN("1.2.840.113549.1.9.1", Email) + ' rsadsi + ' pkcs + ' pkcs9 + ' eMailAddress + On Error Resume Next + sz10 = certHelper.GenerateKeyPair(sessionId, _ + FALSE, DN, 0, ClientAuth, FASLE, TRUE, 1)_ + theError = Err.Number + On Error Goto 0 + if (sz10 = Empty OR theError <> 0) Then + sz = "The error '" & Hex(theError) & "' occurred." & chr(13) & _ + chr(10) & "Your credentials could not be generated." + result = MsgBox(sz, 0, "Credentials Enrollment") + Exit Sub + else + TheForm.Request.value = sz10 + TheForm.Submit + end if + End Sub + + Sub Add_RDN(sn, value) + if (value <> "") then + if (DN <> "") then + DN = DN & "; " + end if + DN = DN & sn & "=" & value + end if + End Sub +</SCRIPT> +</BODY> +</HTML> +EOF +-----END ms-enroll.cgi----- + +Second, how to extract the request and feed the certificate back? We need to +"normalize" the base64 encoding of the PKCS#10 format which means +regenerating the lines and wrapping with BEGIN and END line. This is done by +gawk. The request is taken by ca the normal way. Then the cert needs to be +packed into a PKCS#7 structure (note: the use of a CRL is necessary for +crl2pkcs7 as of version 0.6.6. Starting with 0.8.0 it it might probably be +ommited). Finally we need to format the PKCS#7 object and generate the HTML +text. I use two templates to have a clearer script. + +1st note: postit2 is slightly modified from a program I found at ncsa's ftp +site. Grab it from http://www.easterngraphics.com/certs/IX9704/postit2.c. You +need utils.c from there too. + +2nd note: I'm note quite sure wether the gawk script really handles all +possible inputs for the request right! Today I don't use this construction +anymore myself. + +3d note: the cert must be of version 3! This could be done with the nsComment +line in ssleay.cnf... + +------BEGIN ms-gencert.cgi----- +#!/bin/sh +FILE="/tmp/"`date '+%y%m%d%H%M%S'-`$$ +rm -f "$FILE".* + +HOME=`pwd`; export HOME # as ssleay.cnf insists on having such an env var +cd /usr/local/ssl #where demoCA (as named in ssleay.conf) is located + +postit2 -s " " -i 0x0d > "$FILE".inp # process the FORM vars + +SESSION_ID=`gawk '$1 == "SessionId" { print $2; exit }' "$FILE".inp` + +gawk \ + 'BEGIN { \ + OFS = ""; \ + print "-----BEGIN CERTIFICATE REQUEST-----"; \ + req_seen=0 \ + } \ + $1 == "Request" { \ + req_seen=1; \ + if (length($2) == 72) print($2); \ + lastline=$2; \ + next; \ + } \ + { \ + if (req_seen == 1) { \ + if (length($1) >= 72) print($1); \ + else if (length(lastline) < 72) { \ + req_seen=0; \ + print (lastline,$1); \ + } \ + lastline=$1; \ + } \ + } \ + END { \ + print "-----END CERTIFICATE REQUEST-----"; \ + }' > "$FILE".pem < "$FILE".inp + +ssleay ca -batch -in "$FILE".pem -key passwd -out "$FILE".out +ssleay crl2pkcs7 -certfile "$FILE".out -out "$FILE".pkcs7 -in demoCA/crl.pem + +sed s/template_for_sessId/$SESSION_ID/ <ms-enroll2a.html >"$FILE".cert +/usr/local/bin/gawk \ + 'BEGIN { \ + OFS = ""; \ + dq = sprintf("%c",34); \ + } \ + $0 ~ "PKCS7" { next; } \ + { \ + print dq$0dq" & _"; \ + }' <"$FILE".pkcs7 >> "$FILE".cert +cat ms-enroll2b.html >>"$FILE".cert + +echo Content-type: text/html +echo Content-length: `wc -c "$FILE".cert` +echo +cat "$FILE".cert +rm -f "$FILE".* +-----END ms-gencert.cgi----- + +----BEGIN ms-enroll2a.html---- +<HTML><HEAD><TITLE>Certificate Acceptance Test Page</TITLE></HEAD><BODY> + +<OBJECT + classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" + codebase=certenr3.dll + id=certHelper + > +</OBJECT> + +<CENTER> +<H2>Your personal certificate</H2> +<BR><HR WIDTH=50%><BR><P> +Press the button! +<P><INPUT TYPE=BUTTON VALUE="Nimm mich!" NAME="InstallCert"> +</CENTER> +<BR><HR WIDTH=50%><BR> + +<SCRIPT LANGUAGE=VBS> + Sub InstallCert_OnClick + + sessionId = "template_for_sessId" +credentials = "" & _ +----END ms-enroll2a.html---- + +----BEGIN ms-enroll2b.html---- +"" + On Error Resume Next + result = certHelper.AcceptCredentials(sessionId, credentials, 0, +FALSE) + if (IsEmpty(result)) Then + sz = "The error '" & Err.Number & "' occurred." & chr(13) & +chr(10) & "This Digital ID could not be registered." + msgOut = MsgBox(sz, 0, "Credentials Registration Error") + navigate "error.html" + else + sz = "Digital ID successfully registered." + msgOut = MsgBox(sz, 0, "Credentials Registration") + navigate "success.html" + end if + Exit Sub + End Sub +</SCRIPT> +</BODY> +</HTML> +----END ms-enroll2b.html---- + +4.) What do do with the cert? +----------------------------- + +The cert is visible (without restarting MSIE) under the following menu: +View->Options->Security->Personal certs. You can examine it's contents at +least partially. + +To use it for client authentication you need to use SSL3.0 (fortunately +SSLeay supports it with 0.8.0). Furthermore MSIE is told to only supports a +kind of automatic selection of certs (I personally wasn't able to test it +myself). But there is a requirement that the issuer of the server cert and +the issuer of the client cert needs to be the same (according to a developer +from MS). Which means: you need may more then one cert to talk to all +servers... + +I'm sure we will get a bit more experience after ApacheSSL is available for +SSLeay 0.8.8. + + +I hope you enjoyed reading and that in future questions on this topic will +rarely appear on ssl-users@moncom.com ;-) + +Ilmenau, 9th of June 1997 +Holger Reif <reif@prakinf.tu-ilmenau.de> +-- +read you later - Holger Reif +---------------------------------------- Signaturprojekt Deutsche Einheit +TU Ilmenau - Informatik - Telematik (Verdamp lang her) +Holger.Reif@PrakInf.TU-Ilmenau.DE Alt wie ein Baum werden, um ueber +http://Remus.PrakInf.TU-Ilmenau.DE/Reif/ alle 7 Bruecken gehen zu koennen + diff --git a/doc/ns-ca.doc b/doc/ns-ca.doc new file mode 100644 index 0000000000..836883e1a0 --- /dev/null +++ b/doc/ns-ca.doc @@ -0,0 +1,154 @@ +The following documentation was supplied by Jeff Barber, who provided the +patch to the CA program to add this functionality. + +eric +-- +Jeff Barber Email: jeffb@issl.atl.hp.com + +Hewlett Packard Phone: (404) 648-9503 +Internet and System Security Lab Fax: (404) 648-9516 + + oo +---------------------cut /\ here for ns-ca.doc ------------------------------ + +This document briefly describes how to use SSLeay to implement a +certificate authority capable of dynamically serving up client +certificates for version 3.0 beta 5 (and presumably later) versions of +the Netscape Navigator. Before describing how this is done, it's +important to understand a little about how the browser implements its +client certificate support. This is documented in some detail in the +URLs based at <URL:http://home.netscape.com/eng/security/certs.html>. +Here's a brief overview: + +- The Navigator supports a new HTML tag "KEYGEN" which will cause + the browser to generate an RSA key pair when you submit a form + containing the tag. The public key, along with an optional + challenge (supposedly provided for use in certificate revocation + but I don't use it) is signed, DER-encoded, base-64 encoded + and sent to the web server as the value of the variable + whose NAME is provided in the KEYGEN tag. The private key is + stored by the browser in a local key database. + + This "Signed Public Key And Challenge" (SPKAC) arrives formatted + into 64 character lines (which are of course URL-encoded when + sent via HTTP -- i.e. spaces, newlines and most punctuatation are + encoded as "%HH" where HH is the hex equivalent of the ASCII code). + Note that the SPKAC does not contain the other usual attributes + of a certificate request, especially the subject name fields. + These must be otherwise encoded in the form for submission along + with the SPKAC. + +- Either immediately (in response to this form submission), or at + some later date (a real CA will probably verify your identity in + some way before issuing the certificate), a web server can send a + certificate based on the public key and other attributes back to + the browser by encoding it in DER (the binary form) and sending it + to the browser as MIME type: + "Content-type: application/x-x509-user-cert" + + The browser uses the public key encoded in the certificate to + associate the certificate with the appropriate private key in + its local key database. Now, the certificate is "installed". + +- When a server wants to require authentication based on client + certificates, it uses the right signals via the SSL protocol to + trigger the Navigator to ask you which certificate you want to + send. Whether the certificate is accepted is dependent on CA + certificates and so forth installed in the server and is beyond + the scope of this document. + + +Now, here's how the SSLeay package can be used to provide client +certficates: + +- You prepare a file for input to the SSLeay ca application. + The file contains a number of "name = value" pairs that identify + the subject. The names here are the same subject name component + identifiers used in the CA section of the lib/ssleay.conf file, + such as "emailAddress", "commonName" "organizationName" and so + forth. Both the long version and the short version (e.g. "Email", + "CN", "O") can be used. + + One more name is supported: this one is "SPKAC". Its value + is simply the value of the base-64 encoded SPKAC sent by the + browser (with all the newlines and other space charaters + removed -- and newline escapes are NOT supported). + + [ As of SSLeay 0.6.4, multiple lines are supported. + Put a \ at the end of each line and it will be joined with the + previous line with the '\n' removed - eay ] + + Here's a sample input file: + +C = US +SP = Georgia +O = Some Organization, Inc. +OU = Netscape Compatibility Group +CN = John X. Doe +Email = jxdoe@someorg.com +SPKAC = MIG0MGAwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAwmk6FMJ4uAVIYbcvIOx5+bDGTfvL8X5gE+R67ccMk6rCSGbVQz2cetyQtnI+VIs0NwdD6wjuSuVtVFbLoHonowIDAQABFgAwDQYJKoZIhvcNAQEEBQADQQBFZDUWFl6BJdomtN1Bi53mwijy1rRgJ4YirF15yBEDM3DjAQkKXHYOIX+qpz4KXKnl6EYxTnGSFL5wWt8X2iyx + +- You execute the ca command (either from a CGI program run out of + the web server, or as a later manual task) giving it the above + file as input. For example, if the file were named /tmp/cert.req, + you'd run: + $SSLDIR/bin/ca -spkac /tmp/cert.req -out /tmp/cert + + The output is in DER format (binary) if a -out argument is + provided, as above; otherwise, it's in the PEM format (base-64 + encoded DER). Also, the "-batch" switch is implied by the + "-spkac" so you don't get asked whether to complete the signing + (probably it shouldn't work this way but I was only interested + in hacking together an online CA that could be used for issuing + test certificates). + + The "-spkac" capability doesn't support multiple files (I think). + + Any CHALLENGE provided in the SPKAC is simply ignored. + + The interactions between the identification fields you provide + and those identified in your lib/ssleay.conf are the same as if + you did an ordinary "ca -in infile -out outfile" -- that is, if + something is marked as required in the ssleay.conf file and it + isn't found in the -spkac file, the certificate won't be issued. + +- Now, you pick up the output from /tmp/cert and pass it back to + the Navigator prepending the Content-type string described earlier. + +- In order to run the ca command out of a CGI program, you must + provide a password to decrypt the CA's private key. You can + do this by using "echo MyKeyPassword | $SSLDIR/bin/ca ..." + I think there's a way to not encrypt the key file in the first + place, but I didn't see how to do that, so I made a small change + to the library that allows the password to be accepted from a pipe. + Either way is UTTERLY INSECURE and a real CA would never do that. + + [ You can use the 'ssleay rsa' command to remove the password + from the private key, or you can use the '-key' option to the + ca command to specify the decryption key on the command line + or use the -nodes option when generating the key. + ca will try to clear the command line version of the password + but for quite a few operating systems, this is not possible. + - eric ] + +So, what do you have to do to make use of this stuff to create an online +demo CA capability with SSLeay? + +1 Create an HTML form for your users. The form should contain + fields for all of the required or optional fields in ssleay.conf. + The form must contain a KEYGEN tag somewhere with at least a NAME + attribute. + +2 Create a CGI program to process the form input submitted by the + browser. The CGI program must URL-decode the variables and create + the file described above, containing subject identification info + as well as the SPKAC block. It should then run the the ca program + with the -spkac option. If it works (check the exit status), + return the new certificate with the appropriate MIME type. If not, + return the output of the ca command with MIME type "text/plain". + +3 Set up your web server to accept connections signed by your demo + CA. This probably involves obtaining the PEM-encoded CA certificate + (ordinarily in $SSLDIR/CA/cacert.pem) and installing it into a + server database. See your server manual for instructions. + diff --git a/doc/obj.doc b/doc/obj.doc new file mode 100644 index 0000000000..bad347c936 --- /dev/null +++ b/doc/obj.doc @@ -0,0 +1,69 @@ +The Object library. + +As part of my Crypto library, I found I required a method of identifying various +objects. These objects normally had 3 different values associated with +them, a short text name, a long (or lower case) text name, and an +ASN.1 Object Identifier (which is a sequence of numbers). +This library contains a static list of objects and functions to lookup +according to one type and to return the other types. + +To use these routines, 'Object.h' needs to be included. + +For each supported object, #define entries are defined as follows +#define SN_Algorithm "Algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 38 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +SN_ stands for short name. +LN_ stands for either long name or lowercase name. +NID_ stands for Numeric ID. I each object has a unique NID and this + should be used internally to identify objects. +OBJ_ stands for ASN.1 Object Identifier or ASN1_OBJECT as defined in the + ASN1 routines. These values are used in ASN1 encoding. + +The following functions are to be used to return pointers into a static +definition of these types. What this means is "don't try to free() any +pointers returned from these functions. + +ASN1_OBJECT *OBJ_nid2obj( +int n); + Return the ASN1_OBJECT that corresponds to a NID of n. + +char *OBJ_nid2ln( +int n); + Return the long/lower case name of the object represented by the + NID of n. + +char *OBJ_nid2sn( +int n); + Return the short name for the object represented by the NID of n. + +ASN1_OBJECT *OBJ_dup( +ASN1_OBJECT *o); + Duplicate and return a new ASN1_OBJECT that is the same as the + passed parameter. + +int OBJ_obj2nid( +ASN1_OBJECT *o); + Given ASN1_OBJECT o, return the NID that corresponds. + +int OBJ_ln2nid( +char *s); + Given the long/lower case name 's', return the NID of the object. + +int OBJ_sn2nid( +char *s); + Given the short name 's', return the NID of the object. + +char *OBJ_bsearch( +char *key, +char *base, +int num, +int size, +int (*cmp)()); + Since I have come across a few platforms that do not have the + bsearch() function, OBJ_bsearch is my version of that function. + Feel free to use this function, but you may as well just use the + normal system bsearch(3) if it is present. This version also + has tolerance of being passed NULL pointers. diff --git a/doc/rand.doc b/doc/rand.doc new file mode 100644 index 0000000000..da02a07f64 --- /dev/null +++ b/doc/rand.doc @@ -0,0 +1,141 @@ +My Random number library. + +These routines can be used to generate pseudo random numbers and can be +used to 'seed' the pseudo random number generator (RNG). The RNG make no +effort to reproduce the same random number stream with each execution. +Various other routines in the SSLeay library 'seed' the RNG when suitable +'random' input data is available. Read the section at the end for details +on the design of the RNG. + +void RAND_bytes( +unsigned char *buf, +int num); + This routine puts 'num' random bytes into 'buf'. One should make + sure RAND_seed() has been called before using this routine. + +void RAND_seed( +unsigned char *buf, +int num); + This routine adds more 'seed' data the RNG state. 'num' bytes + are added to the RNG state, they are taken from 'buf'. This + routine can be called with sensitive data such as user entered + passwords. This sensitive data is in no way recoverable from + the RAND library routines or state. Try to pass as much data + from 'random' sources as possible into the RNG via this function. + Also strongly consider using the RAND_load_file() and + RAND_write_file() routines. + +void RAND_cleanup(); + When a program has finished with the RAND library, if it so + desires, it can 'zero' all RNG state. + +The following 3 routines are convenience routines that can be used to +'save' and 'restore' data from/to the RNG and it's state. +Since the more 'random' data that is feed as seed data the better, why not +keep it around between executions of the program? Of course the +application should pass more 'random' data in via RAND_seed() and +make sure no-one can read the 'random' data file. + +char *RAND_file_name( +char *buf, +int size); + This routine returns a 'default' name for the location of a 'rand' + file. The 'rand' file should keep a sequence of random bytes used + to initialise the RNG. The filename is put in 'buf'. Buf is 'size' + bytes long. Buf is returned if things go well, if they do not, + NULL is returned. The 'rand' file name is generated in the + following way. First, if there is a 'RANDFILE' environment + variable, it is returned. Second, if there is a 'HOME' environment + variable, $HOME/.rand is returned. Third, NULL is returned. NULL + is also returned if a buf would overflow. + +int RAND_load_file( +char *file, +long number); + This function 'adds' the 'file' into the RNG state. It does this by + doing a RAND_seed() on the value returned from a stat() system call + on the file and if 'number' is non-zero, upto 'number' bytes read + from the file. The number of bytes passed to RAND_seed() is returned. + +int RAND_write_file( +char *file), + RAND_write_file() writes N random bytes to the file 'file', where + N is the size of the internal RND state (currently 1k). + This is a suitable method of saving RNG state for reloading via + RAND_load_file(). + +What follows is a description of this RNG and a description of the rational +behind it's design. + +It should be noted that this RNG is intended to be used to generate +'random' keys for various ciphers including generation of DH and RSA keys. + +It should also be noted that I have just created a system that I am happy with. +It may be overkill but that does not worry me. I have not spent that much +time on this algorithm so if there are glaring errors, please let me know. +Speed has not been a consideration in the design of these routines. + +First up I will state the things I believe I need for a good RNG. +1) A good hashing algorithm to mix things up and to convert the RNG 'state' + to random numbers. +2) An initial source of random 'state'. +3) The state should be very large. If the RNG is being used to generate + 4096 bit RSA keys, 2 2048 bit random strings are required (at a minimum). + If your RNG state only has 128 bits, you are obviously limiting the + search space to 128 bits, not 2048. I'm probably getting a little + carried away on this last point but it does indicate that it may not be + a bad idea to keep quite a lot of RNG state. It should be easier to + break a cipher than guess the RNG seed data. +4) Any RNG seed data should influence all subsequent random numbers + generated. This implies that any random seed data entered will have + an influence on all subsequent random numbers generated. +5) When using data to seed the RNG state, the data used should not be + extractable from the RNG state. I believe this should be a + requirement because one possible source of 'secret' semi random + data would be a private key or a password. This data must + not be disclosed by either subsequent random numbers or a + 'core' dump left by a program crash. +6) Given the same initial 'state', 2 systems should deviate in their RNG state + (and hence the random numbers generated) over time if at all possible. +7) Given the random number output stream, it should not be possible to determine + the RNG state or the next random number. + + +The algorithm is as follows. + +There is global state made up of a 1023 byte buffer (the 'state'), a +working message digest ('md') and a counter ('count'). + +Whenever seed data is added, it is inserted into the 'state' as +follows. + The input is chopped up into units of 16 bytes (or less for + the last block). Each of these blocks is run through the MD5 + message digest. The data passed to the MD5 digest is the + current 'md', the same number of bytes from the 'state' + (the location determined by in incremented looping index) as + the current 'block' and the new key data 'block'. The result + of this is kept in 'md' and also xored into the 'state' at the + same locations that were used as input into the MD5. + I believe this system addresses points 1 (MD5), 3 (the 'state'), + 4 (via the 'md'), 5 (by the use of MD5 and xor). + +When bytes are extracted from the RNG, the following process is used. +For each group of 8 bytes (or less), we do the following, + Input into MD5, the top 8 bytes from 'md', the byte that are + to be overwritten by the random bytes and bytes from the + 'state' (incrementing looping index). From this digest output + (which is kept in 'md'), the top (upto) 8 bytes are + returned to the caller and the bottom (upto) 8 bytes are xored + into the 'state'. + Finally, after we have finished 'generation' random bytes for the + called, 'count' (which is incremented) and 'md' are fed into MD5 and + the results are kept in 'md'. + I believe the above addressed points 1 (use of MD5), 6 (by + hashing into the 'state' the 'old' data from the caller that + is about to be overwritten) and 7 (by not using the 8 bytes + given to the caller to update the 'state', but they are used + to update 'md'). + +So of the points raised, only 2 is not addressed, but sources of +random data will always be a problem. + diff --git a/doc/rc2.doc b/doc/rc2.doc new file mode 100644 index 0000000000..efab015bd1 --- /dev/null +++ b/doc/rc2.doc @@ -0,0 +1,165 @@ +The RC2 library. + +RC2 is a block cipher that operates on 64bit (8 byte) quantities. It +uses variable size key, but 128bit (16 byte) key would normally be considered +good. It can be used in all the modes that DES can be used. This +library implements the ecb, cbc, cfb64, ofb64 modes. + +I have implemented this library from an article posted to sci.crypt on +11-Feb-1996. I personally don't know how far to trust the RC2 cipher. +While it is capable of having a key of any size, not much reseach has +publically been done on it at this point in time (Apr-1996) +since the cipher has only been public for a few months :-) +It is of a similar speed to DES and IDEA, so unless it is required for +meeting some standard (SSLv2, perhaps S/MIME), it would probably be advisable +to stick to IDEA, or for the paranoid, Tripple DES. + +Mind you, having said all that, I should mention that I just read alot and +implement ciphers, I'm a 'babe in the woods' when it comes to evaluating +ciphers :-). + +For all calls that have an 'input' and 'output' variables, they can be the +same. + +This library requires the inclusion of 'rc2.h'. + +All of the encryption functions take what is called an RC2_KEY as an +argument. An RC2_KEY is an expanded form of the RC2 key. +For all modes of the RC2 algorithm, the RC2_KEY used for +decryption is the same one that was used for encryption. + +The define RC2_ENCRYPT is passed to specify encryption for the functions +that require an encryption/decryption flag. RC2_DECRYPT is passed to +specify decryption. + +Please note that any of the encryption modes specified in my DES library +could be used with RC2. I have only implemented ecb, cbc, cfb64 and +ofb64 for the following reasons. +- ecb is the basic RC2 encryption. +- cbc is the normal 'chaining' form for block ciphers. +- cfb64 can be used to encrypt single characters, therefore input and output + do not need to be a multiple of 8. +- ofb64 is similar to cfb64 but is more like a stream cipher, not as + secure (not cipher feedback) but it does not have an encrypt/decrypt mode. +- If you want triple RC2, thats 384 bits of key and you must be totally + obsessed with security. Still, if you want it, it is simple enough to + copy the function from the DES library and change the des_encrypt to + RC2_encrypt; an exercise left for the paranoid reader :-). + +The functions are as follows: + +void RC2_set_key( +RC2_KEY *ks; +int len; +unsigned char *key; +int bits; + RC2_set_key converts an 'len' byte key into a RC2_KEY. + A 'ks' is an expanded form of the 'key' which is used to + perform actual encryption. It can be regenerated from the RC2 key + so it only needs to be kept when encryption or decryption is about + to occur. Don't save or pass around RC2_KEY's since they + are CPU architecture dependent, 'key's are not. RC2 is an + interesting cipher in that it can be used with a variable length + key. 'len' is the length of 'key' to be used as the key. + A 'len' of 16 is recomended. The 'bits' argument is an + interesting addition which I only found out about in Aug 96. + BSAFE uses this parameter to 'limit' the number of bits used + for the key. To use the 'key' unmodified, set bits to 1024. + This is what old versions of my RC2 library did (SSLeay 0.6.3). + RSAs BSAFE library sets this parameter to be 128 if 128 bit + keys are being used. So to be compatable with BSAFE, set it + to 128, if you don't want to reduce RC2's key length, leave it + at 1024. + +void RC2_encrypt( +unsigned long *data, +RC2_KEY *key, +int encrypt); + This is the RC2 encryption function that gets called by just about + every other RC2 routine in the library. You should not use this + function except to implement 'modes' of RC2. I say this because the + functions that call this routine do the conversion from 'char *' to + long, and this needs to be done to make sure 'non-aligned' memory + access do not occur. + Data is a pointer to 2 unsigned long's and key is the + RC2_KEY to use. Encryption or decryption is indicated by 'encrypt'. + which can have the values RC2_ENCRYPT or RC2_DECRYPT. + +void RC2_ecb_encrypt( +unsigned char *in, +unsigned char *out, +RC2_KEY *key, +int encrypt); + This is the basic Electronic Code Book form of RC2 (in DES this + mode is called Electronic Code Book so I'm going to use the term + for rc2 as well. + Input is encrypted into output using the key represented by + key. Depending on the encrypt, encryption or + decryption occurs. Input is 8 bytes long and output is 8 bytes. + +void RC2_cbc_encrypt( +unsigned char *in, +unsigned char *out, +long length, +RC2_KEY *ks, +unsigned char *ivec, +int encrypt); + This routine implements RC2 in Cipher Block Chaining mode. + Input, which should be a multiple of 8 bytes is encrypted + (or decrypted) to output which will also be a multiple of 8 bytes. + The number of bytes is in length (and from what I've said above, + should be a multiple of 8). If length is not a multiple of 8, bad + things will probably happen. ivec is the initialisation vector. + This function updates iv after each call so that it can be passed to + the next call to RC2_cbc_encrypt(). + +void RC2_cfb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +RC2_KEY *schedule, +unsigned char *ivec, +int *num, +int encrypt); + This is one of the more useful functions in this RC2 library, it + implements CFB mode of RC2 with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + 'Encrypt' is used to indicate encryption or decryption. + CFB64 mode operates by using the cipher to generate a stream + of bytes which is used to encrypt the plain text. + The cipher text is then encrypted to generate the next 64 bits to + be xored (incrementally) with the next 64 bits of plain + text. As can be seen from this, to encrypt or decrypt, + the same 'cipher stream' needs to be generated but the way the next + block of data is gathered for encryption is different for + encryption and decryption. + +void RC2_ofb64_encrypt( +unsigned char *in, +unsigned char *out, +long length, +RC2_KEY *schedule, +unsigned char *ivec, +int *num); + This functions implements OFB mode of RC2 with 64bit feedback. + This allows you to encrypt an arbitrary number of bytes, + you do not require 8 byte padding. Each call to this + routine will encrypt the input bytes to output and then update ivec + and num. Num contains 'how far' we are though ivec. + This is in effect a stream cipher, there is no encryption or + decryption mode. + +For reading passwords, I suggest using des_read_pw_string() from my DES library. +To generate a password from a text string, I suggest using MD5 (or MD2) to +produce a 16 byte message digest that can then be passed directly to +RC2_set_key(). + +===== +For more information about the specific RC2 modes in this library +(ecb, cbc, cfb and ofb), read the section entitled 'Modes of DES' from the +documentation on my DES library. What is said about DES is directly +applicable for RC2. + diff --git a/doc/rc4.doc b/doc/rc4.doc new file mode 100644 index 0000000000..4b2897eb74 --- /dev/null +++ b/doc/rc4.doc @@ -0,0 +1,44 @@ +The RC4 library. +RC4 is a stream cipher that operates on a byte stream. It can be used with +any length key but I would recommend normally using 16 bytes. + +This library requires the inclusion of 'rc4.h'. + +The RC4 encryption function takes what is called an RC4_KEY as an argument. +The RC4_KEY is generated by the RC4_set_key function from the key bytes. + +RC4, being a stream cipher, does not have an encryption or decryption mode. +It produces a stream of bytes that the input stream is xor'ed against and +so decryption is just a case of 'encrypting' again with the same key. + +I have only put in one 'mode' for RC4 which is the normal one. This means +there is no initialisation vector and there is no feedback of the cipher +text into the cipher. This implies that you should not ever use the +same key twice if you can help it. If you do, you leave yourself open to +known plain text attacks; if you know the plain text and +corresponding cipher text in one message, all messages that used the same +key can have the cipher text decoded for the corresponding positions in the +cipher stream. + +The main positive feature of RC4 is that it is a very fast cipher; about 4 +times faster that DES. This makes it ideally suited to protocols where the +key is randomly chosen, like SSL. + +The functions are as follows: + +void RC4_set_key( +RC4_KEY *key; +int len; +unsigned char *data); + This function initialises the RC4_KEY structure with the key passed + in 'data', which is 'len' bytes long. The key data can be any + length but 16 bytes seems to be a good number. + +void RC4( +RC4_KEY *key; +unsigned long len; +unsigned char *in; +unsigned char *out); + Do the actual RC4 encryption/decryption. Using the 'key', 'len' + bytes are transformed from 'in' to 'out'. As mentioned above, + decryption is the operation as encryption. diff --git a/doc/readme b/doc/readme new file mode 100644 index 0000000000..824d4fd0e2 --- /dev/null +++ b/doc/readme @@ -0,0 +1,6 @@ +This is the old 0.6.6 docuementation. Most of the cipher stuff is still +relevent but I'm working (very slowly) on new docuemtation. +The current version can be found online at + +http://www.cryptsoft.com/ssleay/doc + diff --git a/doc/ref.doc b/doc/ref.doc new file mode 100644 index 0000000000..211559900d --- /dev/null +++ b/doc/ref.doc @@ -0,0 +1,48 @@ +I have lots more references etc, and will update this list in the future, +30 Aug 1996 - eay + + +SSL The SSL Protocol - from Netscapes. + +RC4 Newsgroups: sci.crypt + From: sterndark@netcom.com (David Sterndark) + Subject: RC4 Algorithm revealed. + Message-ID: <sternCvKL4B.Hyy@netcom.com> + +RC2 Newsgroups: sci.crypt + From: pgut01@cs.auckland.ac.nz (Peter Gutmann) + Subject: Specification for Ron Rivests Cipher No.2 + Message-ID: <4fk39f$f70@net.auckland.ac.nz> + +MD2 RFC1319 The MD2 Message-Digest Algorithm +MD5 RFC1321 The MD5 Message-Digest Algorithm + +X509 Certificates + RFC1421 Privacy Enhancement for Internet Electronic Mail: Part I + RFC1422 Privacy Enhancement for Internet Electronic Mail: Part II + RFC1423 Privacy Enhancement for Internet Electronic Mail: Part III + RFC1424 Privacy Enhancement for Internet Electronic Mail: Part IV + +RSA and various standard encoding + PKCS#1 RSA Encryption Standard + PKCS#5 Password-Based Encryption Standard + PKCS#7 Cryptographic Message Syntax Standard + A Layman's Guide to a Subset of ASN.1, BER, and DER + An Overview of the PKCS Standards + Some Examples of the PKCS Standards + +IDEA Chapter 3 The Block Cipher IDEA + +RSA, prime number generation and bignum algorithms + Introduction To Algorithms, + Thomas Cormen, Charles Leiserson, Ronald Rivest, + Section 29 Arithmetic Circuits + Section 33 Number-Theoretic Algorithms + +Fast Private Key algorithm + Fast Decipherment Algorithm for RSA Public-Key Cryptosystem + J.-J. Quisquater and C. Couvreur, Electronics Letters, + 14th October 1982, Vol. 18 No. 21 + +Prime number generation and bignum algorithms. + PGP-2.3a diff --git a/doc/req.1 b/doc/req.1 new file mode 100644 index 0000000000..684fda580e --- /dev/null +++ b/doc/req.1 @@ -0,0 +1,137 @@ +The 'req' command is used to manipulate and deal with pkcs#10 +certificate requests. + +It's default mode of operation is to load a certificate and then +write it out again. + +By default the 'req' is read from stdin in 'PEM' format. +The -inform option can be used to specify 'pem' format or 'der' +format. PEM format is the base64 encoding of the DER format. + +By default 'req' then writes the request back out. -outform can be used +to indicate the desired output format, be it 'pem' or 'der'. + +To specify an input file, use the '-in' option and the '-out' option +can be used to specify the output file. + +If you wish to perform a command and not output the certificate +request afterwards, use the '-noout' option. + +When a certificate is loaded, it can be printed in a human readable +ascii format via the '-text' option. + +To check that the signature on a certificate request is correct, use +the '-verify' option to make sure that the private key contained in the +certificate request corresponds to the signature. + +Besides the default mode, there is also the 'generate a certificate +request' mode. There are several flags that trigger this mode. + +-new will generate a new RSA key (if required) and then prompts +the user for details for the certificate request. +-newkey has an argument that is the number of bits to make the new +key. This function also triggers '-new'. + +The '-new' option can have a key to use specified instead of having to +load one, '-key' is used to specify the file containg the key. +-keyform can be used to specify the format of the key. Only +'pem' and 'der' formats are supported, later, 'netscape' format may be added. + +Finally there is the '-x509' options which makes req output a self +signed x509 certificate instead of a certificate request. + +Now as you may have noticed, there are lots of default options that +cannot be specified via the command line. They are held in a 'template' +or 'configuration file'. The -config option specifies which configuration +file to use. See conf.doc for details on the syntax of this file. + +The req command uses the 'req' section of the config file. + +--- +# The following variables are defined. For this example I will populate +# the various values +[ req ] +default_bits = 512 # default number of bits to use. +default_keyfile = testkey.pem # Where to write the generated keyfile + # if not specified. +distinguished_name= req_dn # The section that contains the + # information about which 'object' we + # want to put in the DN. +attributes = req_attr # The objects we want for the + # attributes field. +encrypt_rsa_key = no # Should we encrypt newly generated + # keys. I strongly recommend 'yes'. + +# The distinguished name section. For the following entries, the +# object names must exist in the SSLeay header file objects.h. If they +# do not, they will be silently ignored. The entries have the following +# format. +# <object_name> => string to prompt with +# <object_name>_default => default value for people +# <object_name>_value => Automatically use this value for this field. +# <object_name>_min => minimum number of characters for data (def. 0) +# <object_name>_max => maximum number of characters for data (def. inf.) +# All of these entries are optional except for the first one. +[ req_dn ] +countryName = Country Name (2 letter code) +countryName_default = AU + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Queensland + +localityName = Locality Name (eg, city) + +organizationName = Organization Name (eg, company) +organizationName_default = Mincom Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = MTR + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 40 + +# The next section is the attributes section. This is exactly the +# same as for the previous section except that the resulting objects are +# put in the attributes field. +[ req_attr ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +---- +Also note that the order that attributes appear in this file is the +order they will be put into the distinguished name. + +Once this request has been generated, it can be sent to a CA for +certifying. + +---- +A few quick examples.... + +To generate a new request and a new key +req -new + +To generate a new request and a 1058 bit key +req -newkey 1058 + +To generate a new request using a pre-existing key +req -new -key key.pem + +To generate a self signed x509 certificate from a certificate +request using a supplied key, and we want to see the text form of the +output certificate (which we will put in the file selfSign.pem +req -x509 -in req.pem -key key.pem -text -out selfSign.pem + +Verify that the signature is correct on a certificate request. +req -verify -in req.pem + +Verify that the signature was made using a specified public key. +req -verify -in req.pem -key key.pem + +Print the contents of a certificate request +req -text -in req.pem diff --git a/doc/rsa.doc b/doc/rsa.doc new file mode 100644 index 0000000000..f899a39bb8 --- /dev/null +++ b/doc/rsa.doc @@ -0,0 +1,133 @@ +The RSA encryption and utility routines. + +The RSA routines are built on top of a big number library (the BN library). +There are support routines in the X509 library for loading and manipulating +the various objects in the RSA library. When errors are returned, read +about the ERR library for how to access the error codes. + +All RSA encryption is done according to the PKCS-1 standard which is +compatible with PEM and RSAref. This means that any values being encrypted +must be less than the size of the modulus in bytes, minus 10, bytes long. + +This library uses RAND_bytes()() for it's random data, make sure to feed +RAND_seed() with lots of interesting and varied data before using these +routines. + +The RSA library has one specific data type, the RSA structure. +It is composed of 8 BIGNUM variables (see the BN library for details) and +can hold either a private RSA key or a public RSA key. +Some RSA libraries have different structures for public and private keys, I +don't. For my libraries, a public key is determined by the fact that the +RSA->d value is NULL. These routines will operate on any size RSA keys. +While I'm sure 4096 bit keys are very very secure, they take a lot longer +to process that 1024 bit keys :-). + +The function in the RSA library are as follows. + +RSA *RSA_new(); + This function creates a new RSA object. The sub-fields of the RSA + type are also malloced so you should always use this routine to + create RSA variables. + +void RSA_free( +RSA *rsa); + This function 'frees' an RSA structure. This routine should always + be used to free the RSA structure since it will also 'free' any + sub-fields of the RSA type that need freeing. + +int RSA_size( +RSA *rsa); + This function returns the size of the RSA modulus in bytes. Why do + I need this you may ask, well the reason is that when you encrypt + with RSA, the output string will be the size of the RSA modulus. + So the output for the RSA_encrypt and the input for the RSA_decrypt + routines need to be RSA_size() bytes long, because this is how many + bytes are expected. + +For the following 4 RSA encryption routines, it should be noted that +RSA_private_decrypt() should be used on the output from +RSA_public_encrypt() and RSA_public_decrypt() should be used on +the output from RSA_private_encrypt(). + +int RSA_public_encrypt( +int from_len; +unsigned char *from +unsigned char *to +RSA *rsa); + This function implements RSA public encryption, the rsa variable + should be a public key (but can be a private key). 'from_len' + bytes taken from 'from' and encrypted and put into 'to'. 'to' needs + to be at least RSA_size(rsa) bytes long. The number of bytes + written into 'to' is returned. -1 is returned on an error. The + operation performed is + to = from^rsa->e mod rsa->n. + +int RSA_private_encrypt( +int from_len; +unsigned char *from +unsigned char *to +RSA *rsa); + This function implements RSA private encryption, the rsa variable + should be a private key. 'from_len' bytes taken from + 'from' and encrypted and put into 'to'. 'to' needs + to be at least RSA_size(rsa) bytes long. The number of bytes + written into 'to' is returned. -1 is returned on an error. The + operation performed is + to = from^rsa->d mod rsa->n. + +int RSA_public_decrypt( +int from_len; +unsigned char *from +unsigned char *to +RSA *rsa); + This function implements RSA public decryption, the rsa variable + should be a public key (but can be a private key). 'from_len' + bytes are taken from 'from' and decrypted. The decrypted data is + put into 'to'. The number of bytes encrypted is returned. -1 is + returned to indicate an error. The operation performed is + to = from^rsa->e mod rsa->n. + +int RSA_private_decrypt( +int from_len; +unsigned char *from +unsigned char *to +RSA *rsa); + This function implements RSA private decryption, the rsa variable + should be a private key. 'from_len' bytes are taken + from 'from' and decrypted. The decrypted data is + put into 'to'. The number of bytes encrypted is returned. -1 is + returned to indicate an error. The operation performed is + to = from^rsa->d mod rsa->n. + +int RSA_mod_exp( +BIGNUM *n; +BIGNUM *p; +RSA *rsa); + Normally you will never use this routine. + This is really an internal function which is called by + RSA_private_encrypt() and RSA_private_decrypt(). It performs + n=n^p mod rsa->n except that it uses the 5 extra variables in the + RSA structure to make this more efficient. + +RSA *RSA_generate_key( +int bits; +unsigned long e; +void (*callback)(); + This routine is used to generate RSA private keys. It takes + quite a period of time to run and should only be used to + generate initial private keys that should then be stored + for later use. The passed callback function + will be called periodically so that feedback can be given + as to how this function is progressing. + 'bits' is the length desired for the modulus, so it would be 1024 + to generate a 1024 bit private key. + 'e' is the value to use for the public exponent 'e'. Traditionally + it is set to either 3 or 0x10001. + The callback function (if not NULL) is called in the following + situations. + when we have generated a suspected prime number to test, + callback(0,num1++). When it passes a prime number test, + callback(1,num2++). When it is rejected as one of + the 2 primes required due to gcd(prime,e value) != 0, + callback(2,num3++). When finally accepted as one of the 2 primes, + callback(3,num4++). diff --git a/doc/rsaref.doc b/doc/rsaref.doc new file mode 100644 index 0000000000..0505b76f76 --- /dev/null +++ b/doc/rsaref.doc @@ -0,0 +1,35 @@ +This package can be compiled to use the RSAref library. +This library is not allowed outside of the USA but inside the USA it is +claimed by RSA to be the only RSA public key library that can be used +besides BSAFE.. + +There are 2 files, rsaref/rsaref.c and rsaref/rsaref.h that contain the glue +code to use RSAref. These files were written by looking at the PGP +source code and seeing which routines it used to access RSAref. +I have also been sent by some-one a copy of the RSAref header file that +contains the library error codes. + +[ Jun 1996 update - I have recently gotten hold of RSAref 2.0 from + South Africa and have been doing some performace tests. ] + +They have now been tested against the recently announced RSAEURO +library. + +There are 2 ways to use SSLeay and RSAref. First, to build so that +the programs must be linked with RSAref, add '-DRSAref' to CFLAG in the top +level makefile and -lrsaref (or where ever you are keeping RSAref) to +EX_LIBS. + +To build a makefile via util/mk1mf.pl to do this, use the 'rsaref' option. + +The second method is to build as per normal and link applications with +the RSAglue library. The correct library order would be +cc -o cmd cmd.o -lssl -lRSAglue -lcrypto -lrsaref -ldes +The RSAglue library is built in the rsa directory and is NOT +automatically installed. + +Be warned that the RSAEURO library, that is claimed to be compatible +with RSAref contains a different value for the maximum number of bits +supported. This changes structure sizes and so if you are using +RSAEURO, change the value of RSAref_MAX_BITS in rsa/rsaref.h + diff --git a/doc/s_mult.doc b/doc/s_mult.doc new file mode 100644 index 0000000000..726085bc57 --- /dev/null +++ b/doc/s_mult.doc @@ -0,0 +1,17 @@ +s_mult is a test program I hacked up on a Sunday for testing non-blocking +IO. It has a select loop at it's centre that handles multiple readers +and writers. + +Try the following command +ssleay s_mult -echo -nbio -ssl -v +echo - sends any sent text back to the sender +nbio - turns on non-blocking IO +ssl - accept SSL connections, default is normal text +v - print lots + type Q<cr> to quit + +In another window, run the following +ssleay s_client -pause </etc/termcap + +The pause option puts in a 1 second pause in each read(2)/write(2) call +so the other end will have read()s fail. diff --git a/doc/session.doc b/doc/session.doc new file mode 100644 index 0000000000..ffccb0306e --- /dev/null +++ b/doc/session.doc @@ -0,0 +1,297 @@ +I have just checked over and re-worked the session stuff. +The following brief example will ignore all setup information to do with +authentication. + +Things operate as follows. + +The SSL environment has a 'context', a SSL_CTX structure. This holds the +cached SSL_SESSIONS (which can be reused) and the certificate lookup +information. Each SSL structure needs to be associated with a SSL_CTX. +Normally only one SSL_CTX structure is needed per program. + +SSL_CTX *SSL_CTX_new(void ); +void SSL_CTX_free(SSL_CTX *); +These 2 functions create and destroy SSL_CTX structures + +The SSL_CTX has a session_cache_mode which is by default, +in SSL_SESS_CACHE_SERVER mode. What this means is that the library +will automatically add new session-id's to the cache apon sucsessful +SSL_accept() calls. +If SSL_SESS_CACHE_CLIENT is set, then client certificates are also added +to the cache. +SSL_set_session_cache_mode(ctx,mode) will set the 'mode' and +SSL_get_session_cache_mode(ctx) will get the cache 'mode'. +The modes can be +SSL_SESS_CACHE_OFF - no caching +SSL_SESS_CACHE_CLIENT - only SSL_connect() +SSL_SESS_CACHE_SERVER - only SSL_accept() +SSL_SESS_NO_CACHE_BOTH - Either SSL_accept() or SSL_connect(). +If SSL_SESS_CACHE_NO_AUTO_CLEAR is set, old timed out sessions are +not automatically removed each 255, SSL_connect()s or SSL_accept()s. + +By default, apon every 255 successful SSL_connect() or SSL_accept()s, +the cache is flush. Please note that this could be expensive on +a heavily loaded SSL server, in which case, turn this off and +clear the cache of old entries 'manually' (with one of the functions +listed below) every few hours. Perhaps I should up this number, it is hard +to say. Remember, the '255' new calls is just a mechanims to get called +every now and then, in theory at most 255 new session-id's will have been +added but if 100 are added every minute, you would still have +500 in the cache before any would start being flushed (assuming a 3 minute +timeout).. + +int SSL_CTX_sess_hits(SSL_CTX *ctx); +int SSL_CTX_sess_misses(SSL_CTX *ctx); +int SSL_CTX_sess_timeouts(SSL_CTX *ctx); +These 3 functions return statistics about the SSL_CTX. These 3 are the +number of session id reuses. hits is the number of reuses, misses are the +number of lookups that failed, and timeouts is the number of cached +entries ignored because they had timeouted. + +ctx->new_session_cb is a function pointer to a function of type +int new_session_callback(SSL *ssl,SSL_SESSION *new); +This function, if set in the SSL_CTX structure is called whenever a new +SSL_SESSION is added to the cache. If the callback returns non-zero, it +means that the application will have to do a SSL_SESSION_free() +on the structure (this is +to do with the cache keeping the reference counts correct, without the +application needing to know about it. +The 'active' parameter is the current SSL session for which this connection +was created. + +void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,int (*cb)()); +to set the callback, +int (*cb)() SSL_CTX_sess_get_new_cb(SSL_CTX *ctx) +to get the callback. + +If the 'get session' callback is set, when a session id is looked up and +it is not in the session-id cache, this callback is called. The callback is +of the form +SSL_SESSION *get_session_callback(unsigned char *sess_id,int sess_id_len, + int *copy); + +The get_session_callback is intended to return null if no session id is found. +The reference count on the SSL_SESSION in incremented by the SSL library, +if copy is 1. Otherwise, the reference count is not modified. + +void SSL_CTX_sess_set_get_cb(ctx,cb) sets the callback and +int (*cb)()SSL_CTX_sess_get_get_cb(ctx) returns the callback. + +These callbacks are basically indended to be used by processes to +send their session-id's to other processes. I currently have not implemented +non-blocking semantics for these callbacks, it is upto the appication +to make the callbacks effiecent if they require blocking (perhaps +by 'saving' them and then 'posting them' when control returns from +the SSL_accept(). + +LHASH *SSL_CTX_sessions(SSL_CTX *ctx) +This returns the session cache. The lhash strucutre can be accessed for +statistics about the cache. + +void lh_stats(LHASH *lh, FILE *out); +void lh_node_stats(LHASH *lh, FILE *out); +void lh_node_usage_stats(LHASH *lh, FILE *out); + +can be used to print details about it's activity and current state. +You can also delve directly into the lhash structure for 14 different +counters that are kept against the structure. When I wrote the lhash library, +I was interested in gathering statistics :-). +Have a read of doc/lhash.doc in the SSLeay distribution area for more details +on the lhash library. + +Now as mentioned ealier, when a SSL is created, it needs a SSL_CTX. +SSL * SSL_new(SSL_CTX *); + +This stores a session. A session is secret information shared between 2 +SSL contexts. It will only be created if both ends of the connection have +authenticated their peer to their satisfaction. It basically contains +the information required to use a particular secret key cipher. + +To retrieve the SSL_CTX being used by a SSL, +SSL_CTX *SSL_get_SSL_CTX(SSL *s); + +Now when a SSL session is established between to programs, the 'session' +information that is cached in the SSL_CTX can me manipulated by the +following functions. +int SSL_set_session(SSL *s, SSL_SESSION *session); +This will set the SSL_SESSION to use for the next SSL_connect(). If you use +this function on an already 'open' established SSL connection, 'bad things +will happen'. This function is meaning-less when used on a ssl strucutre +that is just about to be used in a SSL_accept() call since the +SSL_accept() will either create a new session or retrieve one from the +cache. + +SSL_SESSION *SSL_get_session(SSL *s); +This will return the SSL_SESSION for the current SSL, NULL if there is +no session associated with the SSL structure. + +The SSL sessions are kept in the SSL_CTX in a hash table, to remove a +session +void SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c); +and to add one +int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +SSL_CTX_add_session() returns 1 if the session was already in the cache (so it +was not added). +Whenever a new session is created via SSL_connect()/SSL_accept(), +they are automatically added to the cache, depending on the session_cache_mode +settings. SSL_set_session() +does not add it to the cache. Just call SSL_CTX_add_session() if you do want the +session added. For a 'client' this would not normally be the case. +SSL_CTX_add_session() is not normally ever used, except for doing 'evil' things +which the next 2 funtions help you do. + +int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp); +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,unsigned char **pp,long length); +These 2 functions are in the standard ASN1 library form and can be used to +load and save to a byte format, the SSL_SESSION structure. +With these functions, you can save and read these structures to a files or +arbitary byte string. +The PEM_write_SSL_SESSION(fp,x) and PEM_read_SSL_SESSION(fp,x,cb) will +write to a file pointer in base64 encoding. + +What you can do with this, is pass session information between separate +processes. Please note, that you will probably also need to modify the +timeout information on the SSL_SESSIONs. + +long SSL_get_time(SSL_SESSION *s) +will return the 'time' that the session +was loaded. The timeout is relative to this time. This information is +saved when the SSL_SESSION is converted to binarary but it is stored +in as a unix long, which is rather OS dependant, but easy to convert back. + +long SSL_set_time(SSL_SESSION *s,long t) will set the above mentioned time. +The time value is just the value returned from time(3), and should really +be defined by be to be time_t. + +long SSL_get_timeout(SSL_SESSION *s); +long SSL_set_timeout(SSL_SESSION *s,long t); +These 2 retrieve and set the timeout which is just a number of secconds +from the 'SSL_get_time()' value. When this time period has elapesed, +the session will no longer be in the cache (well it will actually be removed +the next time it is attempted to be retrieved, so you could 'bump' +the timeout so it remains valid). +The 'time' and 'timeout' are set on a session when it is created, not reset +each time it is reused. If you did wish to 'bump it', just after establishing +a connection, do a +SSL_set_time(ssl,time(NULL)); + +You can also use +SSL_CTX_set_timeout(SSL_CTX *ctx,unsigned long t) and +SSL_CTX_get_timeout(SSL_CTX *ctx) to manipulate the default timeouts for +all SSL connections created against a SSL_CTX. If you set a timeout in +an SSL_CTX, all new SSL's created will inherit the timeout. It can be over +written by the SSL_set_timeout(SSL *s,unsigned long t) function call. +If you 'set' the timeout back to 0, the system default will be used. + +SSL_SESSION *SSL_SESSION_new(); +void SSL_SESSION_free(SSL_SESSION *ses); +These 2 functions are used to create and dispose of SSL_SESSION functions. +You should not ever normally need to use them unless you are using +i2d_SSL_SESSION() and/or d2i_SSL_SESSION(). If you 'load' a SSL_SESSION +via d2i_SSL_SESSION(), you will need to SSL_SESSION_free() it. +Both SSL_set_session() and SSL_CTX_add_session() will 'take copies' of the +structure (via reference counts) when it is passed to them. + +SSL_CTX_flush_sessions(ctx,time); +The first function will clear all sessions from the cache, which have expired +relative to 'time' (which could just be time(NULL)). + +SSL_CTX_flush_sessions(ctx,0); +This is a special case that clears everything. + +As a final comment, a 'session' is not enough to establish a new +connection. If a session has timed out, a certificate and private key +need to have been associated with the SSL structure. +SSL_copy_session_id(SSL *to,SSL *from); will copy not only the session +strucutre but also the private key and certificate associated with +'from'. + +EXAMPLES. + +So lets play at being a wierd SSL server. + +/* setup a context */ +ctx=SSL_CTX_new(); + +/* Lets load some session from binary into the cache, why one would do + * this is not toally clear, but passing between programs does make sense + * Perhaps you are using 4096 bit keys and are happy to keep them + * valid for a week, to avoid the RSA overhead of 15 seconds, I'm not toally + * sure, perhaps this is a process called from an SSL inetd and this is being + * passed to the application. */ +session=d2i_SSL_SESSION(....) +SSL_CTX_add_session(ctx,session); + +/* Lets even add a session from a file */ +session=PEM_read_SSL_SESSION(....) +SSL_CTX_add_session(ctx,session); + +/* create a new SSL structure */ +ssl=SSL_new(ctx); + +/* At this point we want to be able to 'create' new session if + * required, so we need a certificate and RSAkey. */ +SSL_use_RSAPrivateKey_file(ssl,...) +SSL_use_certificate_file(ssl,...) + +/* Now since we are a server, it make little sence to load a session against + * the ssl strucutre since a SSL_accept() will either create a new session or + * grab an existing one from the cache. */ + +/* grab a socket descriptor */ +fd=accept(...); + +/* associated it with the ssl strucutre */ +SSL_set_fd(ssl,fd); + +SSL_accept(ssl); /* 'do' SSL using out cert and RSA key */ + +/* Lets print out the session details or lets save it to a file, + * perhaps with a secret key cipher, so that we can pass it to the FBI + * when they want to decode the session :-). While we have RSA + * this does not matter much but when I do SSLv3, this will allow a mechanism + * for the server/client to record the information needed to decode + * the traffic that went over the wire, even when using Diffie-Hellman */ +PEM_write_SSL_SESSION(SSL_get_session(ssl),stdout,....) + +Lets 'connect' back to the caller using the same session id. + +ssl2=SSL_new(ctx); +fd2=connect(them); +SSL_set_fd(ssl2,fd2); +SSL_set_session(ssl2,SSL_get_session(ssl)); +SSL_connect(ssl2); + +/* what the hell, lets accept no more connections using this session */ +SSL_CTX_remove_session(SSL_get_SSL_CTX(ssl),SSL_get_session(ssl)); + +/* we could have just as easily used ssl2 since they both are using the + * same session. + * You will note that both ssl and ssl2 are still using the session, and + * the SSL_SESSION structure will be free()ed when both ssl and ssl2 + * finish using the session. Also note that you could continue to initiate + * connections using this session by doing SSL_get_session(ssl) to get the + * existing session, but SSL_accept() will not be able to find it to + * use for incoming connections. + * Of corse, the session will timeout at the far end and it will no + * longer be accepted after a while. The time and timeout are ignored except + * by SSL_accept(). */ + +/* Since we have had our server running for 10 weeks, and memory is getting + * short, perhaps we should clear the session cache to remove those + * 100000 session entries that have expired. Some may consider this + * a memory leak :-) */ + +SSL_CTX_flush_sessions(ctx,time(NULL)); + +/* Ok, after a bit more time we wish to flush all sessions from the cache + * so that all new connections will be authenticated and incure the + * public key operation overhead */ + +SSL_CTX_flush_sessions(ctx,0); + +/* As a final note, to copy everything to do with a SSL, use */ +SSL_copy_session_id(SSL *to,SSL *from); +/* as this also copies the certificate and RSA key so new session can + * be established using the same details */ + diff --git a/doc/sha.doc b/doc/sha.doc new file mode 100644 index 0000000000..895fa182ed --- /dev/null +++ b/doc/sha.doc @@ -0,0 +1,52 @@ +The SHA (Secure Hash Algorithm) library. +SHA is a message digest algorithm that can be used to condense an arbitrary +length message down to a 20 byte hash. The functions all need to be passed +a SHA_CTX which is used to hold the SHA context during multiple SHA_Update() +function calls. The normal method of use for this library is as follows +This library contains both SHA and SHA-1 digest algorithms. SHA-1 is +an update to SHA (which should really be called SHA-0 now) which +tweaks the algorithm slightly. The SHA-1 algorithm is used by simply +using SHA1_Init(), SHA1_Update(), SHA1_Final() and SHA1() instead of the +SHA*() calls + +SHA_Init(...); +SHA_Update(...); +... +SHA_Update(...); +SHA_Final(...); + +This library requires the inclusion of 'sha.h'. + +The functions are as follows: + +void SHA_Init( +SHA_CTX *c); + This function needs to be called to initiate a SHA_CTX structure for + use. + +void SHA_Update( +SHA_CTX *c; +unsigned char *data; +unsigned long len); + This updates the message digest context being generated with 'len' + bytes from the 'data' pointer. The number of bytes can be any + length. + +void SHA_Final( +unsigned char *md; +SHA_CTX *c; + This function is called when a message digest of the data digested + with SHA_Update() is wanted. The message digest is put in the 'md' + array and is SHA_DIGEST_LENGTH (20) bytes long. + +unsigned char *SHA( +unsigned char *d; +unsigned long n; +unsigned char *md; + This function performs a SHA_Init(), followed by a SHA_Update() + followed by a SHA_Final() (using a local SHA_CTX). + The resulting digest is put into 'md' if it is not NULL. + Regardless of the value of 'md', the message + digest is returned from the function. If 'md' was NULL, the message + digest returned is being stored in a static structure. + diff --git a/doc/speed.doc b/doc/speed.doc new file mode 100644 index 0000000000..11dfa85f08 --- /dev/null +++ b/doc/speed.doc @@ -0,0 +1,96 @@ +To get an idea of the performance of this library, use +ssleay speed + +perl util/sp-diff.pl file1 file2 + +will print out the relative differences between the 2 files which are +expected to be the output from the speed program. + +The performace of the library is very dependant on the Compiler +quality and various flags used to build. + +--- + +These are some numbers I did comparing RSAref and SSLeay on a Pentium 100. +[ These numbers are all out of date, as of SSL - 0.6.1 the RSA +operations are about 2 times faster, so check the version number ] + +RSA performance. + +SSLeay 0.6.0 +Pentium 100, 32meg, Windows NT Workstation 3.51 +linux - gcc v 2.7.0 -O3 -fomit-frame-pointer -m486 +and +Windows NT - Windows NT 3.51 - Visual C++ 4.1 - 586 code + 32bit assember +Windows 3.1 - Windows NT 3.51 - Visual C++ 1.52c - 286 code + 32bit assember +NT Dos Shell- Windows NT 3.51 - Visual C++ 1.52c - 286 code + 16bit assember + +Times are how long it takes to do an RSA private key operation. + + 512bits 1024bits +------------------------------- +SSLeay NT dll 0.042s 0.202s see above +SSLeay linux 0.046s 0.218s Assember inner loops (normal build) +SSLeay linux 0.067s 0.380s Pure C code with BN_LLONG defined +SSLeay W3.1 dll 0.108s 0.478s see above +SSLeay linux 0.109s 0.713s C without BN_LLONG. +RSAref2.0 linux 0.149s 0.936s +SSLeay MS-DOS 0.197s 1.049s see above + +486DX66, 32meg, Windows NT Server 3.51 + 512bits 1024bits +------------------------------- +SSLeay NT dll 0.084s 0.495s <- SSLeay 0.6.3 +SSLeay NT dll 0.154s 0.882s +SSLeay W3.1 dll 0.335s 1.538s +SSLeay MS-DOS 0.490s 2.790s + +What I find cute is that I'm still faster than RSAref when using standard C, +without using the 'long long' data type :-), %35 faster for 512bit and we +scale up to 3.2 times faster for the 'default linux' build. I should mention +that people should 'try' to use either x86-lnx.s (elf), x86-lnxa.s or +x86-sol.s for any x86 based unix they are building on. The only problems +with be with syntax but the performance gain is quite large, especially for +servers. The code is very simple, you just need to modify the 'header'. + +The message is, if you are stuck using RSAref, the RSA performance will be +bad. Considering the code was compiled for a pentium, the 486DX66 number +would indicate 'Use RSAref and turn you Pentium 100 into a 486DX66' :-). +[ As of verson 0.6.1, it would be correct to say 'turn you pentium 100 + into a 486DX33' :-) ] + +I won't tell people if the DLL's are using RSAref or my stuff if no-one +asks :-). + +eric + +PS while I know I could speed things up further, I will probably not do + so due to the effort involved. I did do some timings on the + SSLeay bignum format -> RSAref number format conversion that occurs + each time RSAref is used by SSLeay, and the numbers are trivial. + 0.00012s a call for 512bit vs 0.149s for the time spent in the function. + 0.00018s for 1024bit vs 0.938s. Insignificant. + So the 'way to go', to support faster RSA libraries, if people are keen, + is to write 'glue' code in a similar way that I do for RSAref and send it + to me :-). + My base library still has the advantage of being able to operate on + any size numbers, and is not that far from the performance from the + leaders in the field. (-%30?) + [ Well as of 0.6.1 I am now the leader in the filed on x86 (we at + least very close :-) ] + + I suppose I should also mention some other numbers RSAref numbers, again + on my Pentium. + DES CBC EDE-DES MD5 + RSAref linux 830k/s 302k/s 4390k/s + SSLeay linux 855k/s 319k/s 10025k/s + SSLeay NT 1158k/s 410k/s 10470k/s + SSLeay w31 378k/s 143k/s 2383k/s (fully 16bit) + + Got to admit that Visual C++ 4.[01] is a damn fine compiler :-) +-- +Eric Young | BOOL is tri-state according to Bill Gates. +AARNet: eay@cryptsoft.com | RTFM Win32 GetMessage(). + + + diff --git a/doc/ssl-ciph.doc b/doc/ssl-ciph.doc new file mode 100644 index 0000000000..33a7e41f0e --- /dev/null +++ b/doc/ssl-ciph.doc @@ -0,0 +1,84 @@ +This is a quick high level summery of how things work now. + +Each SSLv2 and SSLv3 cipher is composed of 4 major attributes plus a few extra +minor ones. + +They are 'The key exchange algorithm', which is RSA for SSLv2 but can also +be Diffle-Hellman for SSLv3. + +An 'Authenticion algorithm', which can be RSA, Diffle-Helman, DSS or +none. + +The cipher + +The MAC digest. + +A cipher can also be an export cipher and is either an SSLv2 or a +SSLv3 ciphers. + +To specify which ciphers to use, one can either specify all the ciphers, +one at a time, or use 'aliases' to specify the preference and order for +the ciphers. + +There are a large number of aliases, but the most importaint are +kRSA, kDHr, kDHd and kEDH for key exchange types. + +aRSA, aDSS, aNULL and aDH for authentication +DES, 3DES, RC4, RC2, IDEA and eNULL for ciphers +MD5, SHA0 and SHA1 digests + +Now where this becomes interesting is that these can be put together to +specify the order and ciphers you wish to use. + +To speed this up there are also aliases for certian groups of ciphers. +The main ones are +SSLv2 - all SSLv2 ciphers +SSLv3 - all SSLv3 ciphers +EXP - all export ciphers +LOW - all low strngth ciphers (no export ciphers, normally single DES) +MEDIUM - 128 bit encryption +HIGH - Triple DES + +These aliases can be joined in a : separated list which specifies to +add ciphers, move them to the current location and delete them. + +A simpler way to look at all of this is to use the 'ssleay ciphers -v' command. +The default library cipher spec is +!ADH:RC4+RSA:HIGH:MEDIUM:LOW:EXP:+SSLv2:+EXP +which means, first, remove from consideration any ciphers that do not +authenticate. Next up, use ciphers using RC4 and RSA. Next include the HIGH, +MEDIUM and the LOW security ciphers. Finish up by adding all the export +ciphers on the end, then 'pull' all the SSLv2 and export ciphers to +the end of the list. + +The results are +$ ssleay ciphers -v '!ADH:RC4+RSA:HIGH:MEDIUM:LOW:EXP:+SSLv2:+EXP' + +RC4-SHA SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=SHA1 +RC4-MD5 SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=MD5 +EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Au=RSA Enc=3DES(168) Mac=SHA1 +EDH-DSS-DES-CBC3-SHA SSLv3 Kx=DH Au=DSS Enc=3DES(168) Mac=SHA1 +DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1 +IDEA-CBC-MD5 SSLv3 Kx=RSA Au=RSA Enc=IDEA(128) Mac=SHA1 +EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH Au=RSA Enc=DES(56) Mac=SHA1 +EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH Au=DSS Enc=DES(56) Mac=SHA1 +DES-CBC-SHA SSLv3 Kx=RSA Au=RSA Enc=DES(56) Mac=SHA1 +DES-CBC3-MD5 SSLv2 Kx=RSA Au=RSA Enc=3DES(168) Mac=MD5 +DES-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=DES(56) Mac=MD5 +IDEA-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=IDEA(128) Mac=MD5 +RC2-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=RC2(128) Mac=MD5 +RC4-MD5 SSLv2 Kx=RSA Au=RSA Enc=RC4(128) Mac=MD5 +EXP-EDH-RSA-DES-CBC SSLv3 Kx=DH(512) Au=RSA Enc=DES(40) Mac=SHA1 export +EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512) Au=DSS Enc=DES(40) Mac=SHA1 export +EXP-DES-CBC-SHA SSLv3 Kx=RSA(512) Au=RSA Enc=DES(40) Mac=SHA1 export +EXP-RC2-CBC-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export +EXP-RC4-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export +EXP-RC2-CBC-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export +EXP-RC4-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export + +I would recoment people use the 'ssleay ciphers -v "text"' +command to check what they are going to use. + +Anyway, I'm falling asleep here so I'll do some more tomorrow. + +eric diff --git a/doc/ssl.doc b/doc/ssl.doc new file mode 100644 index 0000000000..1f89cd5db2 --- /dev/null +++ b/doc/ssl.doc @@ -0,0 +1,172 @@ +SSL_CTX_sessions(SSL_CTX *ctx) - the session-id hash table. + +/* Session-id cache stats */ +SSL_CTX_sess_number +SSL_CTX_sess_connect +SSL_CTX_sess_connect_good +SSL_CTX_sess_accept +SSL_CTX_sess_accept_good +SSL_CTX_sess_hits +SSL_CTX_sess_cb_hits +SSL_CTX_sess_misses +SSL_CTX_sess_timeouts + +/* Session-id application notification callbacks */ +SSL_CTX_sess_set_new_cb +SSL_CTX_sess_get_new_cb +SSL_CTX_sess_set_get_cb +SSL_CTX_sess_get_get_cb + +/* Session-id cache operation mode */ +SSL_CTX_set_session_cache_mode +SSL_CTX_get_session_cache_mode + +/* Set default timeout values to use. */ +SSL_CTX_set_timeout +SSL_CTX_get_timeout + +/* Global SSL initalisation informational callback */ +SSL_CTX_set_info_callback +SSL_CTX_get_info_callback +SSL_set_info_callback +SSL_get_info_callback + +/* If the SSL_accept/SSL_connect returned with -1, these indicate when + * we should re-call *. +SSL_want +SSL_want_nothing +SSL_want_read +SSL_want_write +SSL_want_x509_lookup + +/* Where we are in SSL initalisation, used in non-blocking, perhaps + * have a look at ssl/bio_ssl.c */ +SSL_state +SSL_is_init_finished +SSL_in_init +SSL_in_connect_init +SSL_in_accept_init + +/* Used to set the 'inital' state so SSL_in_connect_init and SSL_in_accept_init + * can be used to work out which function to call. */ +SSL_set_connect_state +SSL_set_accept_state + +/* Where to look for certificates for authentication */ +SSL_set_default_verify_paths /* calles SSL_load_verify_locations */ +SSL_load_verify_locations + +/* get info from an established connection */ +SSL_get_session +SSL_get_certificate +SSL_get_SSL_CTX + +SSL_CTX_new +SSL_CTX_free +SSL_new +SSL_clear +SSL_free + +SSL_CTX_set_cipher_list +SSL_get_cipher +SSL_set_cipher_list +SSL_get_cipher_list +SSL_get_shared_ciphers + +SSL_accept +SSL_connect +SSL_read +SSL_write + +SSL_debug + +SSL_get_read_ahead +SSL_set_read_ahead +SSL_set_verify + +SSL_pending + +SSL_set_fd +SSL_set_rfd +SSL_set_wfd +SSL_set_bio +SSL_get_fd +SSL_get_rbio +SSL_get_wbio + +SSL_use_RSAPrivateKey +SSL_use_RSAPrivateKey_ASN1 +SSL_use_RSAPrivateKey_file +SSL_use_PrivateKey +SSL_use_PrivateKey_ASN1 +SSL_use_PrivateKey_file +SSL_use_certificate +SSL_use_certificate_ASN1 +SSL_use_certificate_file + +ERR_load_SSL_strings +SSL_load_error_strings + +/* human readable version of the 'state' of the SSL connection. */ +SSL_state_string +SSL_state_string_long +/* These 2 report what kind of IO operation the library was trying to + * perform last. Probably not very usefull. */ +SSL_rstate_string +SSL_rstate_string_long + +SSL_get_peer_certificate + +SSL_SESSION_new +SSL_SESSION_print_fp +SSL_SESSION_print +SSL_SESSION_free +i2d_SSL_SESSION +d2i_SSL_SESSION + +SSL_get_time +SSL_set_time +SSL_get_timeout +SSL_set_timeout +SSL_copy_session_id +SSL_set_session +SSL_CTX_add_session +SSL_CTX_remove_session +SSL_CTX_flush_sessions + +BIO_f_ssl + +/* used to hold information as to why a certificate verification failed */ +SSL_set_verify_result +SSL_get_verify_result + +/* can be used by the application to associate data with an SSL structure. + * It needs to be 'free()ed' by the application */ +SSL_set_app_data +SSL_get_app_data + +/* The following all set values that are kept in the SSL_CTX but + * are used as the default values when an SSL session is created. + * They are over writen by the relevent SSL_xxxx functions */ + +/* SSL_set_verify */ +void SSL_CTX_set_default_verify + +/* This callback, if set, totaly overrides the normal SSLeay verification + * functions and should return 1 on sucesss and 0 on failure */ +void SSL_CTX_set_cert_verify_callback + +/* The following are the same as the equivilent SSL_xxx functions. + * Only one copy of this information is kept and if a particular + * SSL structure has a local override, it is totally separate structure. + */ +int SSL_CTX_use_RSAPrivateKey +int SSL_CTX_use_RSAPrivateKey_ASN1 +int SSL_CTX_use_RSAPrivateKey_file +int SSL_CTX_use_PrivateKey +int SSL_CTX_use_PrivateKey_ASN1 +int SSL_CTX_use_PrivateKey_file +int SSL_CTX_use_certificate +int SSL_CTX_use_certificate_ASN1 +int SSL_CTX_use_certificate_file + diff --git a/doc/ssl_ctx.doc b/doc/ssl_ctx.doc new file mode 100644 index 0000000000..508394e75f --- /dev/null +++ b/doc/ssl_ctx.doc @@ -0,0 +1,68 @@ +This is now a bit dated, quite a few of the SSL_ functions could be +SSL_CTX_ functions. I will update this in the future. 30 Aug 1996 + +From eay@orb.mincom.oz.au Mon Dec 11 21:37:08 1995 +Received: by orb.mincom.oz.au id AA00696 + (5.65c/IDA-1.4.4 for eay); Mon, 11 Dec 1995 11:37:08 +1000 +Date: Mon, 11 Dec 1995 11:37:08 +1000 (EST) +From: Eric Young <eay@mincom.oz.au> +X-Sender: eay@orb +To: sameer <sameer@c2.org> +Cc: Eric Young <eay@mincom.oz.au> +Subject: Re: PEM_readX509 oesn't seem to be working +In-Reply-To: <199512110102.RAA12521@infinity.c2.org> +Message-Id: <Pine.SOL.3.91.951211112115.28608D-100000@orb> +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Status: RO +X-Status: + +On Sun, 10 Dec 1995, sameer wrote: +> OK, that's solved. I've found out that it is saying "no +> certificate set" in SSL_accept because s->conn == NULL +> so there is some place I need to initialize s->conn that I am +> not initializing it. + +The full order of things for a server should be. + +ctx=SSL_CTX_new(); + +/* The next line should not really be using ctx->cert but I'll leave it + * this way right now... I don't want a X509_ routine to know about an SSL + * structure, there should be an SSL_load_verify_locations... hmm, I may + * add it tonight. + */ +X509_load_verify_locations(ctx->cert,CAfile,CApath); + +/* Ok now for each new connection we do the following */ +con=SSL_new(ctx); +SSL_set_fd(con,s); +SSL_set_verify(con,verify,verify_callback); + +/* set the certificate and private key to use. */ +SSL_use_certificate_ASN1(con,X509_certificate); +SSL_use_RSAPrivateKey_ASN1(con,RSA_private_key); + +SSL_accept(con); + +SSL_read(con)/SSL_write(con); + +There is a bit more than that but that is basically the structure. + +Create a context and specify where to lookup certificates. + +foreach connection + { + create a SSL structure + set the certificate and private key + do a SSL_accept + + we should now be ok + } + +eric +-- +Eric Young | Signature removed since it was generating +AARNet: eay@mincom.oz.au | more followups than the message contents :-) + + diff --git a/doc/ssleay.doc b/doc/ssleay.doc new file mode 100644 index 0000000000..a0e86aef7c --- /dev/null +++ b/doc/ssleay.doc @@ -0,0 +1,213 @@ +SSLeay: a cryptographic kitchen sink. + +1st December 1995 +Way back at the start of April 1995, I was looking for a mindless +programming project. A friend of mine (Tim Hudson) said "why don't you do SSL, +it has DES encryption in it and I would not mind using it in a SSL telnet". +While it was true I had written a DES library in previous years, litle +did I know what an expansive task SSL would turn into. + +First of all, the SSL protocol contains DES encryption. Well and good. My +DES library was fast and portable. It also contained the RSA's RC4 stream +cipher. Again, not a problem, some-one had just posted to sci.crypt +something that was claimed to be RC4. It also contained IDEA, I had the +specifications, not a problem to implement. MD5, an RFC, trivial, at most +I could spend a week or so trying to see if I could speed up the +implementation. All in all a nice set of ciphers. +Then the first 'expantion of the scope', RSA public key +encryption. Since I did not knowing a thing about public key encryption +or number theory, this appeared quite a daunting task. Just writing a +big number library would be problomatic in itself, let alone making it fast. +At this point the scope of 'implementing SSL' expands eponentialy. +First of all, the RSA private keys were being kept in ASN.1 format. +Thankfully the RSA PKCS series of documents explains this format. So I now +needed to be able to encode and decode arbitary ASN.1 objects. The Public +keys were embeded in X509 certificates. Hmm... these are not only +ASN.1 objects but they make up a heirachy of authentication. To +authenticate a X509 certificate one needs to retrieve it's issuers +certificate etc etc. Hmm..., so I also need to implement some kind +of certificate management software. I would also have to implement +software to authenticate certificates. At this point the support code made +the SSL part of my library look quite small. +Around this time, the first version of SSLeay was released. + +Ah, but here was the problem, I was not happy with the code so far. As may +have become obvious, I had been treating all of this as a learning +exersize, so I have completely written the library myself. As such, due +to the way it had grown like a fungus, much of the library was not +'elagent' or neat. There were global and static variables all over the +place, the SSL part did not even handle non-blocking IO. +The Great rewrite began. + +As of this point in time, the 'Great rewrite' has almost finished. So what +follows is an approximate list of what is actually SSLeay 0.5.0 + +/********* This needs to be updated for 0.6.0+ *************/ + +--- +The library contains the following routines. Please note that most of these +functions are not specfic for SSL or any other particular cipher +implementation. I have tried to make all the routines as general purpose +as possible. So you should not think of this library as an SSL +implemtation, but rather as a library of cryptographic functions +that also contains SSL. I refer to each of these function groupings as +libraries since they are often capable of functioning as independant +libraries + +First up, the general ciphers and message digests supported by the library. + +MD2 rfc???, a standard 'by parts' interface to this algorithm. +MD5 rfc???, the same type of interface as for the MD2 library except a + different algorithm. +SHA THe Secure Hash Algorithm. Again the same type of interface as + MD2/MD5 except the digest is 20 bytes. +SHA1 The 'revised' version of SHA. Just about identical to SHA except + for one tweak of an inner loop. +DES This is my libdes library that has been floating around for the last + few years. It has been enhanced for no other reason than completeness. + It now supports ecb, cbc, cfb, ofb, cfb64, ofb64 in normal mode and + triple DES modes of ecb, cbc, cfb64 and ofb64. cfb64 and ofb64 are + functional interfaces to the 64 bit modes of cfb and ofb used in + such a way thay they function as single character interfaces. +RC4 The RSA Inc. stream cipher. +RC2 The RSA Inc. block cipher. +IDEA An implmentation of the IDEA cipher, the library supports ecb, cbc, + cfb64 and ofb64 modes of operation. + +Now all the above mentioned ciphers and digests libraries support high +speed, minimal 'crap in the way' type interfaces. For fastest and +lowest level access, these routines should be used directly. + +Now there was also the matter of public key crypto systems. These are +based on large integer arithmatic. + +BN This is my large integer library. It supports all the normal + arithmentic operations. It uses malloc extensivly and as such has + no limits of the size of the numbers being manipulated. If you + wish to use 4000 bit RSA moduli, these routines will handle it. + This library also contains routines to 'generate' prime numbers and + to test for primality. The RSA and DH libraries sit on top of this + library. As of this point in time, I don't support SHA, but + when I do add it, it will just sit on top of the routines contained + in this library. +RSA This implements the RSA public key algorithm. It also contains + routines that will generate a new private/public key pair. + All the RSA functions conform to the PKCS#1 standard. +DH This is an implementation of the + Diffie-Hellman protocol. There are all the require routines for + the protocol, plus extra routines that can be used to generate a + strong prime for use with a specified generator. While this last + routine is not generally required by applications implementing DH, + It is present for completeness and because I thing it is much + better to be able to 'generate' your own 'magic' numbers as oposed + to using numbers suplied by others. I conform to the PKCS#3 + standard where required. + +You may have noticed the preceeding section mentions the 'generation' of +prime numbers. Now this requries the use of 'random numbers'. + +RAND This psuedo-random number library is based on MD5 at it's core + and a large internal state (2k bytes). Once you have entered enough + seed data into this random number algorithm I don't feel + you will ever need to worry about it generating predictable output. + Due to the way I am writing a portable library, I have left the + issue of how to get good initial random seed data upto the + application but I do have support routines for saving and loading a + persistant random number state for use between program runs. + +Now to make all these ciphers easier to use, a higher level +interface was required. In this form, the same function would be used to +encrypt 'by parts', via any one of the above mentioned ciphers. + +EVP The Digital EnVeloPe library is quite large. At it's core are + function to perform encryption and decryption by parts while using + an initial parameter to specify which of the 17 different ciphers + or 4 different message digests to use. On top of these are implmented + the digital signature functions, sign, verify, seal and open. + Base64 encoding of binary data is also done in this library. + +PEM rfc???? describe the format for Privacy Enhanced eMail. + As part of this standard, methods of encoding digital enveloped + data is an ascii format are defined. As such, I use a form of these + to encode enveloped data. While at this point in time full support + for PEM has not been built into the library, a minimal subset of + the secret key and Base64 encoding is present. These reoutines are + mostly used to Ascii encode binary data with a 'type' associated + with it and perhaps details of private key encryption used to + encrypt the data. + +PKCS7 This is another Digital Envelope encoding standard which uses ASN.1 + to encode the data. At this point in time, while there are some + routines to encode and decode this binary format, full support is + not present. + +As Mentioned, above, there are several different ways to encode +data structures. + +ASN1 This library is more a set of primatives used to encode the packing + and unpacking of data structures. It is used by the X509 + certificate standard and by the PKCS standards which are used by + this library. It also contains routines for duplicating and signing + the structures asocisated with X509. + +X509 The X509 library contains routines for packing and unpacking, + verifying and just about every thing else you would want to do with + X509 certificates. + +PKCS7 PKCS-7 is a standard for encoding digital envelope data + structures. At this point in time the routines will load and save + DER forms of these structees. They need to be re-worked to support + the BER form which is the normal way PKCS-7 is encoded. If the + previous 2 sentances don't make much sense, don't worry, this + library is not used by this version of SSLeay anyway. + +OBJ ASN.1 uses 'object identifiers' to identify objects. A set of + functions were requred to translate from ASN.1 to an intenger, to a + character string. This library provieds these translations + +Now I mentioned an X509 library. X509 specified a hieachy of certificates +which needs to be traversed to authenticate particular certificates. + +METH This library is used to push 'methods' of retrieving certificates + into the library. There are some supplied 'methods' with SSLeay + but applications can add new methods if they so desire. + This library has not been finished and is not being used in this + version. + +Now all the above are required for use in the initial point of this project. + +SSL The SSL protocol. This is a full implmentation of SSL v 2. It + support both server and client authentication. SSL v 3 support + will be added when the SSL v 3 specification is released in it's + final form. + +Now quite a few of the above mentioned libraries rely on a few 'complex' +data structures. For each of these I have a library. + +Lhash This is a hash table library which is used extensivly. + +STACK An implemetation of a Stack data structure. + +BUF A simple character array structure that also support a function to + check that the array is greater that a certain size, if it is not, + it is realloced so that is it. + +TXT_DB A simple memory based text file data base. The application can specify + unique indexes that will be enforced at update time. + +CONF Most of the programs written for this library require a configuration + file. Instead of letting programs constantly re-implment this + subsystem, the CONF library provides a consistant and flexable + interface to not only configuration files but also environment + variables. + +But what about when something goes wrong? +The one advantage (and perhaps disadvantage) of all of these +functions being in one library was the ability to implement a +single error reporting system. + +ERR This library is used to report errors. The error system records + library number, function number (in the library) and reason + number. Multiple errors can be reported so that an 'error' trace + is created. The errors can be printed in numeric or textual form. + diff --git a/doc/ssluse.doc b/doc/ssluse.doc new file mode 100644 index 0000000000..2e3a26cbf3 --- /dev/null +++ b/doc/ssluse.doc @@ -0,0 +1,45 @@ +We have an SSL_CTX which contains global information for lots of +SSL connections. The session-id cache and the certificate verificate cache. +It also contains default values for use when certificates are used. + +SSL_CTX + default cipher list + session-id cache + certificate cache + default session-id timeout period + New session-id callback + Required session-id callback + session-id stats + Informational callback + Callback that is set, overrides the SSLeay X509 certificate + verification + The default Certificate/Private Key pair + Default read ahead mode. + Default verify mode and verify callback. These are not used + if the over ride callback mentioned above is used. + +Each SSL can have the following defined for it before a connection is made. + +Certificate +Private key +Ciphers to use +Certificate verify mode and callback +IO object to use in the comunication. +Some 'read-ahead' mode information. +A previous session-id to re-use. + +A connection is made by using SSL_connect or SSL_accept. +When non-blocking IO is being used, there are functions that can be used +to determin where and why the SSL_connect or SSL_accept did not complete. +This information can be used to recall the functions when the 'error' +condition has dissapeared. + +After the connection has been made, information can be retrived about the +SSL session and the session-id values that have been decided apon. +The 'peer' certificate can be retrieved. + +The session-id values include +'start time' +'timeout length' + + diff --git a/doc/stack.doc b/doc/stack.doc new file mode 100644 index 0000000000..7c20b1b664 --- /dev/null +++ b/doc/stack.doc @@ -0,0 +1,96 @@ +The stack data structure is used to store an ordered list of objects. +It is basically misnamed to call it a stack but it can function that way +and that is what I originally used it for. Due to the way element +pointers are kept in a malloc()ed array, the most efficient way to use this +structure is to add and delete elements from the end via sk_pop() and +sk_push(). If you wish to do 'lookups' sk_find() is quite efficient since +it will sort the stack (if required) and then do a binary search to lookup +the requested item. This sorting occurs automatically so just sk_push() +elements on the stack and don't worry about the order. Do remember that if +you do a sk_find(), the order of the elements will change. + +You should never need to 'touch' this structure directly. +typedef struct stack_st + { + unsigned int num; + char **data; + int sorted; + + unsigned int num_alloc; + int (*comp)(); + } STACK; + +'num' holds the number of elements in the stack, 'data' is the array of +elements. 'sorted' is 1 is the list has been sorted, 0 if not. + +num_alloc is the number of 'nodes' allocated in 'data'. When num becomes +larger than num_alloc, data is realloced to a larger size. +If 'comp' is set, it is a function that is used to compare 2 of the items +in the stack. The function should return -1, 0 or 1, depending on the +ordering. + +#define sk_num(sk) ((sk)->num) +#define sk_value(sk,n) ((sk)->data[n]) + +These 2 macros should be used to access the number of elements in the +'stack' and to access a pointer to one of the values. + +STACK *sk_new(int (*c)()); + This creates a new stack. If 'c', the comparison function, is not +specified, the various functions that operate on a sorted 'stack' will not +work (sk_find()). NULL is returned on failure. + +void sk_free(STACK *); + This function free()'s a stack structure. The elements in the +stack will not be freed so one should 'pop' and free all elements from the +stack before calling this function or call sk_pop_free() instead. + +void sk_pop_free(STACK *st; void (*func)()); + This function calls 'func' for each element on the stack, passing +the element as the argument. sk_free() is then called to free the 'stack' +structure. + +int sk_insert(STACK *sk,char *data,int where); + This function inserts 'data' into stack 'sk' at location 'where'. +If 'where' is larger that the number of elements in the stack, the element +is put at the end. This function tends to be used by other 'stack' +functions. Returns 0 on failure, otherwise the number of elements in the +new stack. + +char *sk_delete(STACK *st,int loc); + Remove the item a location 'loc' from the stack and returns it. +Returns NULL if the 'loc' is out of range. + +char *sk_delete_ptr(STACK *st, char *p); + If the data item pointed to by 'p' is in the stack, it is deleted +from the stack and returned. NULL is returned if the element is not in the +stack. + +int sk_find(STACK *st,char *data); + Returns the location that contains a value that is equal to +the 'data' item. If the comparison function was not set, this function +does a linear search. This function actually qsort()s the stack if it is not +in order and then uses bsearch() to do the initial search. If the +search fails,, -1 is returned. For mutliple items with the same +value, the index of the first in the array is returned. + +int sk_push(STACK *st,char *data); + Append 'data' to the stack. 0 is returned if there is a failure +(due to a malloc failure), else 1. This is +sk_insert(st,data,sk_num(st)); + +int sk_unshift(STACK *st,char *data); + Prepend 'data' to the front (location 0) of the stack. This is +sk_insert(st,data,0); + +char *sk_shift(STACK *st); + Return and delete from the stack the first element in the stack. +This is sk_delete(st,0); + +char *sk_pop(STACK *st); + Return and delete the last element on the stack. This is +sk_delete(st,sk_num(sk)-1); + +void sk_zero(STACK *st); + Removes all items from the stack. It does not 'free' +pointers but is a quick way to clear a 'stack of references'. diff --git a/doc/threads.doc b/doc/threads.doc new file mode 100644 index 0000000000..251061e896 --- /dev/null +++ b/doc/threads.doc @@ -0,0 +1,90 @@ +How to compile SSLeay for multi-threading. + +Well basically it is quite simple, set the compiler flags and build. +I have only really done much testing under Solaris and Windows NT. +If you library supports localtime_r() and gmtime_r() add, +-DTHREADS to the makefile parameters. You can probably survive with out +this define unless you are going to have multiple threads generating +certificates at once. It will not affect the SSL side of things. + +The approach I have taken to doing locking is to make the application provide +callbacks to perform locking and so that the SSLeay library can distinguish +between threads (for the error state). + +To have a look at an example program, 'cd mt; vi mttest.c'. +To build under solaris, sh solaris.sh, for Windows NT or Windows 95, +win32.bat + +This will build mttest which will fire up 10 threads that talk SSL +to each other 10 times. +To enable everything to work, the application needs to call + +CRYPTO_set_id_callback(id_function); +CRYPTO_set_locking_callback(locking_function); + +before any multithreading is started. +id_function does not need to be defined under Windows NT or 95, the +correct function will be called if it is not. Under unix, getpid() +is call if the id_callback is not defined, for solaris this is wrong +(since threads id's are not pid's) but under IRIX it is correct +(threads are just processes sharing the data segement). + +The locking_callback is used to perform locking by the SSLeay library. +eg. + +void solaris_locking_callback(mode,type,file,line) +int mode; +int type; +char *file; +int line; + { + if (mode & CRYPTO_LOCK) + mutex_lock(&(lock_cs[type])); + else + mutex_unlock(&(lock_cs[type])); + } + +Now in this case I have used mutexes instead of read/write locks, since they +are faster and there are not many read locks in SSLeay, you may as well +always use write locks. file and line are __FILE__ and __LINE__ from +the compile and can be usefull when debugging. + +Now as you can see, 'type' can be one of a range of values, these values are +defined in crypto/crypto.h +CRYPTO_get_lock_name(type) will return a text version of what the lock is. +There are CRYPTO_NUM_LOCKS locks required, so under solaris, the setup +for multi-threading can be + +static mutex_t lock_cs[CRYPTO_NUM_LOCKS]; + +void thread_setup() + { + int i; + + for (i=0; i<CRYPTO_NUM_LOCKS; i++) + mutex_init(&(lock_cs[i]),USYNC_THREAD,NULL); + CRYPTO_set_id_callback((unsigned long (*)())solaris_thread_id); + CRYPTO_set_locking_callback((void (*)())solaris_locking_callback); + } + +As a final note, under Windows NT or Windows 95, you have to be careful +not to mix the various threaded, unthreaded and debug libraries. +Normally if they are mixed incorrectly, mttest will crash just after printing +out some usage statistics at the end. This is because the +different system libraries use different malloc routines and if +data is malloc()ed inside crypt32.dll or ssl32.dll and then free()ed by a +different library malloc, things get very confused. + +The default SSLeay DLL builds use /MD, so if you use this on your +application, things will work as expected. If you use /MDd, +you will probably have to rebuild SSLeay using this flag. +I should modify util/mk1mf.pl so it does all this correctly, but +this has not been done yet. + +One last warning. Because locking overheads are actually quite large, the +statistics collected against the SSL_CTX for successfull connections etc +are not locked when updated. This does make it possible for these +values to be slightly lower than they should be, if you are +running multithreaded on a multi-processor box, but this does not really +matter much. + diff --git a/doc/txt_db.doc b/doc/txt_db.doc new file mode 100644 index 0000000000..3a5b0d50a1 --- /dev/null +++ b/doc/txt_db.doc @@ -0,0 +1,4 @@ +TXT_DB, a simple text based in memory database. + +It holds rows of ascii data, for which the only special character is '\0'. +The rows can be of an unlimited length. diff --git a/doc/verify b/doc/verify new file mode 100644 index 0000000000..b78d96159d --- /dev/null +++ b/doc/verify @@ -0,0 +1,22 @@ +X509_verify_cert_chain( + CERT_STORE *cert_store, + STACK /* X509 */ *certs, + int *verify_result, + int (*verify_error_callback)() + char *argument_to_callback, /* SSL */ + +app_verify_callback( + char *app_verify_arg, /* from SSL_CTX */ + STACK /* X509 */ *certs, + int *verify_result, + int (*verify_error_callback)() + SSL *s, + +int X509_verify_cert( + CERT_STORE *cert_store, + X509 *x509, + int *verify_result, + int (*verify_error_callback)(), + char *arg, + + diff --git a/doc/why.doc b/doc/why.doc new file mode 100644 index 0000000000..a1ac84bd27 --- /dev/null +++ b/doc/why.doc @@ -0,0 +1,79 @@ +This file is more of a note for other people who wish to understand why +the build environment is the way it is :-). + +The include files 'depend' as follows. +Each of +crypto/*/*.c includes crypto/cryptlib.h +ssl/*.c include ssl/ssl_locl.h +apps/*.c include apps/apps.h +crypto/cryptlib.h, ssl/ssl_locl.h and apps/apps.h +all include e_os.h which contains OS/environment specific information. +If you need to add something todo with a particular environment, +add it to this file. It is worth remembering that quite a few libraries, +like lhash, des, md, sha etc etc do not include crypto/cryptlib.h. This +is because these libraries should be 'independantly compilable' and so I +try to keep them this way. +e_os.h is not so much a part of SSLeay, as the placing in one spot all the +evil OS dependant muck. + +I wanted to automate as many things as possible. This includes +error number generation. A +make errors +will scan the source files for error codes, append them to the correct +header files, and generate the functions to print the text version +of the error numbers. So don't even think about adding error numbers by +hand, put them in the form +XXXerr(XXXX_F_XXXX,YYYY_R_YYYY); +on line and it will be automatically picked up my a make errors. + +In a similar vein, programs to be added into ssleay in the apps directory +just need to have an entry added to E_EXE in makefile.ssl and +everthing will work as expected. Don't edit progs.h by hand. + +make links re-generates the symbolic links that are used. The reason why +I keep everything in its own directory, and don't put all the +test programs and header files in 'test' and 'include' is because I want +to keep the 'sub-libraries' independant. I still 'pull' out +indervidual libraries for use in specific projects where the code is +required. I have used the 'lhash' library in just about every software +project I have worked on :-). + +make depend generates dependancies and +make dclean removes them. + +You will notice that I use perl quite a bit when I could be using 'sed'. +The reason I decided to do this was to just stick to one 'extra' program. +For Windows NT, I have perl and no sed. + +The util/mk1mf.pl program can be used to generate a single makefile. +I use this because makefiles under Microsoft are horrific. +Each C compiler seems to have different linker formats, which have +to be used because the retarted C compilers explode when you do +cl -o file *.o. + +Now some would argue that I should just use the single makefile. I don't +like it during develoment for 2 reasons. First, the actuall make +command takes a long time. For my current setup, if I'm in +crypto/bn and I type make, only the crypto/bn directory gets rebuilt, +which is nice when you are modifying prototypes in bn.h which +half the SSLeay depends on. The second is that to add a new souce file +I just plonk it in at the required spot in the local makefile. This +then alows me to keep things local, I don't need to modify a 'global' +tables (the make for unix, the make for NT, the make for w31...). +When I am ripping apart a library structure, it is nice to only +have to worry about one directory :-). + +Having said all this, for the hell of it I put together 2 files that +#include all the souce code (generated by doing a ls */*.o after a build). +crypto.c takes only 30 seconds to build under NT and 2 minutes under linux +for my pentium100. Much faster that the normal build :-). +Again, the problem is that when using libraries, every program linked +to libcrypto.a would suddenly get 330k of library when it may only need +1k. This technique does look like a nice way to do shared libraries though. + +Oh yes, as a final note, to 'build' a distribution, I just type +make dist. +This cleans and packages everything. The directory needs to be called +SSLeay since the make does a 'cd ..' and renames and tars things up. + + |