int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) { X509_OBJECT *obj; int ret = 1; if (x == NULL) return 0; obj = (X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); if (obj == NULL) { X509err(X509_F_X509_STORE_ADD_CRL, ERR_R_MALLOC_FAILURE); return 0; } obj->type = X509_LU_CRL; obj->data.crl = x; CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); X509_OBJECT_up_ref_count(obj); if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { X509_OBJECT_free_contents(obj); OPENSSL_free(obj); X509err(X509_F_X509_STORE_ADD_CRL, X509_R_CERT_ALREADY_IN_HASH_TABLE); ret = 0; } else sk_X509_OBJECT_push(ctx->objs, obj); CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); return ret; }
int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) { X509_OBJECT *obj; int ret = 1; if (x == NULL) return 0; obj = OPENSSL_malloc(sizeof(*obj)); if (obj == NULL) { X509err(X509_F_X509_STORE_ADD_CERT, ERR_R_MALLOC_FAILURE); return 0; } obj->type = X509_LU_X509; obj->data.x509 = x; CRYPTO_THREAD_write_lock(ctx->lock); X509_OBJECT_up_ref_count(obj); if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { X509_OBJECT_free_contents(obj); OPENSSL_free(obj); X509err(X509_F_X509_STORE_ADD_CERT, X509_R_CERT_ALREADY_IN_HASH_TABLE); ret = 0; } else sk_X509_OBJECT_push(ctx->objs, obj); CRYPTO_THREAD_unlock(ctx->lock); return ret; }
int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) { X509_OBJECT *obj; int ret = 1; if (x == NULL) return 0; obj = (X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); if (obj == NULL) { OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); return 0; } obj->type = X509_LU_CRL; obj->data.crl = x; CRYPTO_MUTEX_lock_write(&ctx->objs_lock); X509_OBJECT_up_ref_count(obj); if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { X509_OBJECT_free_contents(obj); OPENSSL_free(obj); OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE); ret = 0; } else if (!sk_X509_OBJECT_push(ctx->objs, obj)) { X509_OBJECT_free_contents(obj); OPENSSL_free(obj); OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); ret = 0; } CRYPTO_MUTEX_unlock_write(&ctx->objs_lock); return ret; }
int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) { X509_OBJECT *obj; int ret = 1; if (x == NULL) return 0; obj = X509_OBJECT_new(); if (obj == NULL) return 0; obj->type = X509_LU_CRL; obj->data.crl = x; CRYPTO_THREAD_write_lock(ctx->lock); X509_OBJECT_up_ref_count(obj); if (X509_OBJECT_retrieve_match(ctx->objs, obj)) { X509_OBJECT_free(obj); X509err(X509_F_X509_STORE_ADD_CRL, X509_R_CERT_ALREADY_IN_HASH_TABLE); ret = 0; } else sk_X509_OBJECT_push(ctx->objs, obj); CRYPTO_THREAD_unlock(ctx->lock); return ret; }
/** Verification callback function to override any existing callbacks in OpenSSL for intermediate certificate supports. @param[in] Status Original status before calling this callback. @param[in] Context X509 store context. @retval 1 Current X509 certificate is verified successfully. @retval 0 Verification failed. **/ int X509VerifyCb ( IN int Status, IN X509_STORE_CTX *Context ) { X509_OBJECT *Obj; INTN Error; INTN Index; INTN Count; Obj = NULL; Error = (INTN) X509_STORE_CTX_get_error (Context); // // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT and X509_V_ERR_UNABLE_TO_GET_ISSUER_ // CERT_LOCALLY mean a X509 certificate is not self signed and its issuer // can not be found in X509_verify_cert of X509_vfy.c. // In order to support intermediate certificate node, we override the // errors if the certification is obtained from X509 store, i.e. it is // a trusted ceritifcate node that is enrolled by user. // Besides,X509_V_ERR_CERT_UNTRUSTED and X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE // are also ignored to enable such feature. // if ((Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) { Obj = (X509_OBJECT *) malloc (sizeof (X509_OBJECT)); if (Obj == NULL) { return 0; } Obj->type = X509_LU_X509; Obj->data.x509 = Context->current_cert; CRYPTO_w_lock (CRYPTO_LOCK_X509_STORE); if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) { Status = 1; } else { // // If any certificate in the chain is enrolled as trusted certificate, // pass the certificate verification. // if (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { Count = (INTN) sk_X509_num (Context->chain); for (Index = 0; Index < Count; Index++) { Obj->data.x509 = sk_X509_value (Context->chain, (int) Index); if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) { Status = 1; break; } } } } CRYPTO_w_unlock (CRYPTO_LOCK_X509_STORE); } if ((Error == X509_V_ERR_CERT_UNTRUSTED) || (Error == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) { Status = 1; } if (Obj != NULL) { OPENSSL_free (Obj); } return Status; }
/* This function negociates a SSL session with the server. * This function sets the KMO error string. It returns 0, -1, -2, or -3. */ static int knp_negociate_ssl_session(struct knp_query *query, char *cert, k3p_proto *k3p) { int error = 0; SSL_METHOD *ssl_method; BIO *ssl_bio; kmod_log_msg(3, "knp_negociate_ssl_session() called.\n"); /* Create the SSL driver. */ struct knp_ssl_driver *driver = (struct knp_ssl_driver *) kmo_calloc(sizeof(struct knp_ssl_driver)); assert(query->ssl_driver == NULL); query->ssl_driver = driver; ssl_method = SSLv3_client_method(); if (ssl_method == NULL) { kmo_seterror("cannot initialize SSL method"); return -1; } driver->ssl_ctx = SSL_CTX_new(ssl_method); if (driver->ssl_ctx == NULL) { kmo_seterror("cannot initialize SSL context"); return -1; } driver->ssl = SSL_new(driver->ssl_ctx); if (driver->ssl == NULL) { kmo_seterror("cannot initialize SSL session"); return -1; } ssl_bio = BIO_new_socket(query->transfer.fd, BIO_NOCLOSE); if (ssl_bio == NULL) { kmo_seterror("cannot initialize SSL BIO"); return -1; } /* Set SSL BIO. 'ssl_bio' is owned by 'ssl', do not free. */ SSL_set_bio(driver->ssl, ssl_bio, ssl_bio); /* If we have a certificate, set it in SSL. */ if (cert) { int i; BIO *cert_bio = NULL; X509 *cert_obj = NULL; X509_STORE *cert_store = NULL; X509_OBJECT x509_obj; kstr cert_buf; kstr_init(&cert_buf); /* Try. */ do { /* Recreate the certificate. */ kstr_append_cstr(&cert_buf, "-----BEGIN CERTIFICATE-----\n"); kstr_append_cstr(&cert_buf, cert); kstr_append_cstr(&cert_buf, "-----END CERTIFICATE-----\n"); for (i = 0; i < cert_buf.slen; i++) { if (cert_buf.data[i] == '|') { cert_buf.data[i] = '\n'; } } /* Put the certificate text in a buffer. */ cert_bio = BIO_new_mem_buf(cert_buf.data, cert_buf.slen); if (cert_bio == NULL) { kmo_seterror("cannot create SSL BIO for reading SSL certificate"); error = -1; break; } /* Create the certificate object with the buffer data. */ cert_obj = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); if (cert_obj == NULL) { kmo_seterror("cannot create SSL certificate"); error = -1; break; } /* Add the certificate in the certificate store if it is not * already present. */ /* Get the certificate store. */ cert_store = SSL_CTX_get_cert_store(driver->ssl_ctx); if (cert_store == NULL) { kmo_seterror("cannot get SSL certificate store"); error = -1; break; } /* Understanding SSL's API is a daunting task. I've peeked at * the source code and that code should work. For now. Sigh. * Wouldn't it be nice if programmers bothered to make * *library* APIs that are somewhat sane... * * Check if the certificate is already in the store. */ x509_obj.type = X509_LU_X509; x509_obj.data.x509 = cert_obj; /* It seems the certificate is already in the store. */ if (X509_OBJECT_retrieve_match(cert_store->objs, &x509_obj)) { /* Void. */ } /* Add the certificate in the store. We still own cert_obj after * this call. */ else if (X509_STORE_add_cert(cert_store, cert_obj) != 1) { kmo_seterror("cannot store SSL certificate"); error = -1; break; } } while (0); if (cert_obj) X509_free(cert_obj); if (cert_bio) BIO_free(cert_bio); kstr_free(&cert_buf); if (error) return error; } /* If we need a certificate, require the server to send us its certificate. */ SSL_set_verify(driver->ssl, cert ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* Loop until we connect or fail. */ while (1) { error = SSL_connect(driver->ssl); /* We're connected. */ if (error > 0) { error = 0; break; } else { int ssl_error = SSL_get_error(driver->ssl, error); error = 0; /* SSL wants us to wait for reading data. */ if (ssl_error == SSL_ERROR_WANT_READ) { error = knp_query_wait_for_data(query, 1, "SSL negociation read failed", k3p); if (error) return error; } /* SSL wants us to wait for writing data. */ else if (ssl_error == SSL_ERROR_WANT_WRITE) { error = knp_query_wait_for_data(query, 0, "SSL negociation write failed", k3p); if (error) return error; } /* Life is tough. */ else { kmo_seterror("SSL negociation failed: %s", get_ssl_error_string(ssl_error)); return -1; } } } /* Validate the server's certificate as needed. */ if (cert) { /* Check if the server sent us a certificate. */ X509 *peer_cert = SSL_get_peer_certificate(driver->ssl); if (peer_cert == NULL) { kmo_seterror("the server did not send its SSL certificate"); return -1; } X509_free(peer_cert); /* Verify the certificate. */ if (SSL_get_verify_result(driver->ssl) != X509_V_OK) { kmo_seterror("the SSL certificate of the server is invalid"); return -1; } } return 0; }