int X509_verify_cert( X509_STORE_CTX *ctx) EFFECTS: this procedure "verifies" the certificate stored in ctx->cert. This function returns an integer: -1 if there is no certificate for us to verify 0 if there is a malloc failure ?? ... it appears to somehow look-up certificates and sometimes returns stuff from some internal call? X509_LU_RETRY == -1 X509_LU_FAIL == 0 X509_LU_X509 == 1 [according to eay, -1 if you should try again, 0 if fail, 1 if success.] As it processes, it may encounter things which would normally make a certificate "bad". However, the user may specify a callback which can be used to override SSLeay's default opinion of an error. Callback writers should see x509_vfy.h and examine the contents of X509_STORE_CTX (== struct x509_store_state_st) to see what is available when in the callback. Note that a callback may be called multiple times per certificate if there are multiple things wrong with it! NOTES: Entry possibilities: ctx->chain NULL, ctx->chain something. ctx->untrusted NULL, ctx->untrusted something. This function makes use of: ctx->cert : certificate to verify. fails if NULL ctx->ctx->cb : user callback (function pointer). should have prototype: int cb( int ok, X509_STORE_CTX *ctx ). If not set, defaults to the SSLeay provided "null_callback", which simply returns ok. *NB:* This is set in a X509_STORE contained in the X509_STORE_CTX. The X509_STORE_CTX is just used to process a single certificate verification! Users should set this callback to something which examines the current verify state and then does something creative. See below for more details. ctx->chain : the chain of certificates as we proceed down the verification. This parameter is modified. ctx->depth : preset (?). checks up to this many certificates ctx->current_cert : the cert we're currently processing (useful in callback). This parameter is modified. ctx->untrusted : this is used to build up our chain? perhaps optionally provided by the connecting client or server? ctx->last_untrusted : where is this initialized? we either overwrite it or increment it. In the procedure, we have these local variables: cb : the user's callback x : the certificate we are trying to verify. (pushed onto chain) xn : issuer_name of x. depth : ctx->depth (initialized in X509_STORE_CTX_init). Defaults to 10. /* * When our callback is called: * if we have a self signed cert which is the only certificate * in the chain. DEPTH_ZERO_SELF_SIGNED_CERT. Huh. When we get * called here, we don't actually know that its a valid signature. top most cert is not self signed, chain_ss == NULL, ctx->last_untrusted >= num UNABLE_TO_GET_ISSUER_CERT_LOCALLY top most cert is not self signed, chain_ss != NULL, chain_ss didn't issue x, ctx->last_untrusted >= num, UNABLE_TO_GET_ISSUER_CERT_LOCALLY top most cert is not self signed, chain_ss == NULL, ctx->last_untrusted < num UNABLE_TO_GET_ISSUER_CERT top most cert is not self signed, chain_ss != NULL, chain_ss didn't issue x, ctx->last_untrusted < num, UNABLE_TO_GET_ISSUER_CERT top most cert is not self signed, chain_ss != NULL, chain_ss did issue x, SELF_SIGNED_CERT_IN_CHAIN if the top cert is not self signed and it's the last certificate, UNABLE_TO_VERIFY_LEAF_SIGNATURE iterate over these until we're out of certs UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY CERT_SIGNATURE_FAILURE ERROR_IN_CERT_NOT_BEFORE_FIELD (huh? looks like it does this if the time is the same as now.) CERT_NOT_YET_VALID ERROR_IN_CERT_NOT_AFTER_FIELD ERR_CERT_HAS_EXPIRED call callback again with ok = 1 if we made it to here. Not used: X509_V_OK. X509_V_ERR_UNABLE_TO_GET_CRL, X509_V_ERR_UNABLE_TO_DECRYPT_{CERT,CRL}_SIGNATURE, CRL_SIGNATURE_FAILURE, ERROR_IN_CRL_*, OUT_OF_MEM, CERT_CHAIN_TOO_LONG. */ Procedure flow: A. Get a certificate chain. 1. ensure there's a cert to verify 2. create a chain if necessary and insert the cert to verify at the bottom of the stack. [i.e. first in.] 3. Until we have depth certificates (or we reach a self-signed), look up issuers in ctx->untrusted ...?? BUG?? The highest parent are at the top of the stack ctx->chain. We actually appear to just try to find the issuer in the untrusted list and then we exit this do {} while(0) loop. 4. Then we take a look at what we've got in ctx->chain. If the top one is self-signed and is the only cert in our chain, we signal an error to the callback. If the callback says it's ok, we continue, otherwise we get out with a failure. If it is *not* the only cert in the chain, we assign chain_ss to be the top one, pop it off ctx->chain and set x to the next lowest cert. 5. Now, we lookup stuff from our STORE, again until we have depth certs or a self-signed cert. [what about the possible previous self-signed one?] We'll fail variously if we can't find a cert. ** Under what conditions os X509_LU_FAIL returned? what if we get a cert but have no parent certs anywhere but we want to connect anyway? At this point, x is whatever is at the top of ctx->chain. num is the number of certs in the chain. chain_ss is the possible top-certificate ctx->last_untrusted is the highest cert we got from ctx->untrusted. B. Check our new-found certificate chain. 1. If the top cert is not self-signed, and (if the prev top untrusted cert (chain_ss) is not null or the chain_ss is not the issuer of our top cert) then, set our error to UNABLE_TO_GET_ISSUER_CERT (or CERT_LOCALLY, if we found some certs locally that were higher up than the provided ones). otherwise, put chain_ss back into the chain, set that to be the ctx->current_cert and complain about SELF_SIGNED_CERT_IN_CHAIN. Regardless, process the callback. 2. If we're still ok, then call the verification procedure (which is generally internally defined, but can be user overriden. =================================== int SSL_get_cipher_bits( SSL *s, int *alg_bits ) Modifies: alg_bits Effects: Returns the number bits being used for encryption in the connection described by s. If alg_bits != NULL, *alg_bits is also set to this number. If we are using an exportable cipher, this value is 40. If there is no session running, this value is 0. =================================== char *SSL_get_cipher( SSL *s ) Effects: returns a pointer to a string describing the cipher being used to perform the encryption. If there is no session running (or, I suppose if this information has not yet been determined), return NULL. =================================== char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len) Requires: if buf != NULL, buf should be a character buffer of at least 128 bytes. len must be the amount of space in buf. Modifies: buf Effects: Modifies buf to contain a string description of the cipher cipher in buf. If buf is NULL, we will try to allocate 128 bytes to hold it (remember to free() it!). If we can't allocate that much, we'll return "Malloc Error". Notes: there doesn't appear to be a good way to get the current SSL_CIPHER being used out of an SSL. I suppose you could do ssl->session->cipher but that seems like violating abstraction barriers. =================================== int SSL_connect( SSL *s ) Requires: SSL_set_fd has been called to set the fd on s to the right thing. Modifies: s (I think) Effects: does a connect appropriate to the method set in the SSL_CTX that the SSL was created from. =================================== Doing SSL configuration. Verification setup: SSL_CTX_set_verify( SSL_CTX *ctx, int mode, int (*cb)() ) Effects: set the default verify mode to mode and the default verify callback to cb for the context ctx. mode should be one of: /* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options * are 'ored' with SSL_VERIFY_PEER if they are desired */ #define SSL_VERIFY_NONE 0x00 #define SSL_VERIFY_PEER 0x01 #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 #define SSL_VERIFY_CLIENT_ONCE 0x04 The last one appears to only be useful in server context. I'm not really sure about the FAIL_IF_NO_PEER_CERT one. =================================== How do we do RSA key stuff? RSA *RSA_generate_key( int bits, unsigned long e_value, void (*callback)(int, int) ) Effects: generates an rsa key of the size of the key you want. bits specifies how big you want the key to be (traditionally 512, 768 or 1024). e_value is the exponent value (use, for example, RSA_F4 == 0x10001L or RSA_3 == 0x3L). callback is a function which can be used to display information as the key is being generated. For example: void genrsa_cb( int p, int n ) { char c = '*'; if (p == 0) c='.'; else if (p == 1) c='+'; else if (p == 2) c='*'; else if (p == 3) c='\n'; fprintf(stderr, "%c", c); } So, one might do: RSA *rsa = NULL; rsa = RSA_generate_key( size, RSA_F4, NULL ); ========================= sk's are zero based. sk->num is the next available slot (and also the number of things in the stack. ========================= Info callback for SSL_connect() void apps_ssl_info_callback( SSL *s, int where, int ret ); SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); So, this call back is used basically for displaying information about the connection as it progresses. ctx is an SSL_CTX *. Parameters to the callback are as follows: - SSL *s is the current SSL connection. You might do something like SSL_state_string_long(s) or something. - int where is a bit vector which contains bits of state information. It might contain: #define SSL_ST_CONNECT 0x1000 #define SSL_ST_ACCEPT 0x2000 #define SSL_ST_MASK 0x0FFF #define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT) #define SSL_ST_BEFORE 0x4000 #define SSL_ST_OK 0x03 #define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT) #define SSL_CB_LOOP 0x01 #define SSL_CB_EXIT 0x02 #define SSL_CB_READ 0x04 #define SSL_CB_WRITE 0x08 #define SSL_CB_ALERT 0x4000 /* used in callback */ #define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ) #define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE) #define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP) #define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT) #define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP) #define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT) use the ST_MASK if you want to check the state, I guess. - int ret is something. No idea really. It may be set to certain things in response to where. ========================= Certificate callback for SSL_connect() void SSL_CTX_set_client_cert_cb(SSL_CTX ctx, cb) where cb is int callback(SSL *s,X509 **x509, EVP_PKEY **pkey); I assume that this callback is supposed to take the SSL session, derive some information from it, lookup some X509 key and stick that into *x509. The corresponding private key should be stuck in *pkey. The callback needs to allocate the appropriate memory for this and trust that SSLeay frees the memory later. If the callback returns < 0, we fail and want to try again. If it is 1 and *x509 and *pkey point to real things, we're happy and set the key. If it's 0, we just alert that we have no cert. If -1, try again later. The callback should allocate memory as appropriate if *x509 or *pkey are NULL pointers. ======================== Reading RSA keys from disk: PEM_read_RSAPrivateKey( FILE *fp, x, cb ) try: x = NULL. I believe the cb is used to get a password. If cb == NULL, the default cb will be used.