*Thanks for the quick answer*, actually command line is good as it would be
done in a
child process using a secure vault for password creation that no admin knows
anyway or makes up.
No human is involved is always the best solution. Can't trust those humans.
thanks.
I enclosed the correct code solution below for anyone to see how to
programmatically create an OSCP request.
./OCSPrequest -help
Usage:
./OCSPrequest <cert> <issuer root>
eg:
./OCSPrequest 1000.pem ./demoCA/cacert.pem
OCSPrequest.c
============
/**
* cc -o OCSPrequest -Wno-deprecated-declarations
-Wno-pointer-type-mismatch OCSPrequest.c -lcrypto
*
*
* Origin: r redpath
*
*
* The fields in this structure are as follows:
*
* typedef struct {
* char *url;
* X509 *cert;
* X509 *issuer;
* spc_x509store_t *store;
* X509 *sign_cert;
* EVP_PKEY *sign_key;
* long skew;
* long maxage;
* } spc_ocsprequest_t;
*
* url
* Address of the OCSP responder to which to connect; this should always be
a
* URL that specifies either HTTP or HTTPS as the service. For example,
* VeriSign's OCSP responder address is http://ocsp.verisign.com.
*
* cert
* Pointer to the certificate whose revocation status you want to check.
* In many cases, this will likely come from the peer when establishing or
* renegotiating an SSL session.
*
* issuer
* Pointer to the certificate that issued the certificate whose revocation
* status you want to check. This should be a trusted root certificate.
*
* store
* Any information required for building an X509_STORE object internally.
* This object will be used for verifying the OCSP responder's certificate.
* A full discussion of this object can be found in Recipe 10.5, but
basically
* it contains trusted certificates and CRLs that OpenSSL can use to verify
* the validity of the certificate received from the OCSP responder.
*
* sign_cert
* An OCSP request can optionally be signed. Some servers require signed
* requests. Any server will accept a signed request provided that the
server
* is able to verify the signature. If you want the request to be signed,
* this field should be non-NULL and should be a pointer to the certificate
* to use to sign the request. If you are going to sign your request, you
* should use a certificate that has been issued by a CA that is trusted by
* the OCSP responder so that the responder will be able to verify its
validity.
*
* sign_key
* If the sign_cert member is non-NULL, this member must be filled in with
* a pointer to the private key to use in signing the request. It is
ignored
* if the sign_cert member is NULL.
*
* skew
* An OCSP response contains three time fields: thisUpdate, nextUpdate, and
* producedAt. These fields must be checked to determine how reliable the
* results from the responder are. For example, under no circumstance
should
* thisUpdate ever be greater than nextUpdate. However, it is likely that
there
* will be some amount of clock skew between the server and the client.
skew
* defines an acceptable amount of skew in units of seconds. It should be
set
* <to a reasonably low value. In most cases, five seconds should work out
fine.
*
* maxage
* RFC 2560 OCSP responders are allowed to precompute responses to improve
response
* time by eliminating the need to sign a response for every request. There
are
* obvious security implications if a server opts to do this, as we
discussed in
* Recipe 10.1. The producedAt field in the response will contain the time
at which
* the response was computed, whether or not it was precomputed. The maxage
member
* specifies the maximum age in seconds of responses that should be
considered
* acceptable. Setting maxage to 0 will effectively cause the producedAt
field in
* the response to be ignored and any otherwise acceptable response to be
accepted,
* regardless of its age. OpenSSL's command-line ocsp command defaults to
ignoring
* the producedAt field. However, we think it is too risky to accept
precomputed
* responses. Unfortunately, there is no way to completely disable the
acceptance
* of precomputed responses. The closest we can get is to set this value to
one
* second, which is what we recommend you do.
* Querying an OCSP responder is actually a complex operation, even though
we are
* effectively reducing the amount of work necessary for you to a single
function
* call. Because of the complexity of the operation, a number of things can
go wrong,
* and so we have defined a sizable number of possible error codes. In some
cases,
* we have lumped a number of finer-grained errors into a single error
code, but
* the code presented here can easily be expanded to provide more detailed
error
* information.
* ************************/
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ocsp.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
#define SPC_X509STORE_NO_DEFAULT_CAFILE 0x01
#define SPC_X509STORE_NO_DEFAULT_CAPATH 0x02
typedef int (*spc_x509verifycallback_t)(int, X509_STORE_CTX *);
typedef struct {
char *cafile;
char *capath;
char *crlfile;
spc_x509verifycallback_t callback;
STACK_OF(X509) *certs;
STACK_OF(X509_CRL) *crls;
char *use_certfile;
STACK_OF(X509) *use_certs;
char *use_keyfile;
EVP_PKEY *use_key;
int flags;
} spc_x509store_t;
typedef struct {
char *url;
X509 *cert;
X509 *issuer;
spc_x509store_t *store;
X509 *sign_cert;
EVP_PKEY *sign_key;
long skew;
long maxage;
} spc_ocsprequest_t;
typedef enum {
SPC_OCSPRESULT_ERROR_INVALIDRESPONSE = -12,
SPC_OCSPRESULT_ERROR_CONNECTFAILURE = -11,
SPC_OCSPRESULT_ERROR_SIGNFAILURE = -10,
SPC_OCSPRESULT_ERROR_BADOCSPADDRESS = -9,
SPC_OCSPRESULT_ERROR_OUTOFMEMORY = -8,
SPC_OCSPRESULT_ERROR_UNKNOWN = -7,
SPC_OCSPRESULT_ERROR_UNAUTHORIZED = -6,
SPC_OCSPRESULT_ERROR_SIGREQUIRED = -5,
SPC_OCSPRESULT_ERROR_TRYLATER = -3,
SPC_OCSPRESULT_ERROR_INTERNALERROR = -2,
SPC_OCSPRESULT_ERROR_MALFORMEDREQUEST = -1,
SPC_OCSPRESULT_CERTIFICATE_VALID = 0,
SPC_OCSPRESULT_CERTIFICATE_REVOKED = 1
} spc_ocspresult_t;
/**
*
*/
void spc_init_x509store(spc_x509store_t *spc_store) {
spc_store->cafile = 0;
spc_store->capath = 0;
spc_store->crlfile = 0;
spc_store->callback = 0;
spc_store->certs = sk_X509_new_null( );
spc_store->crls = sk_X509_CRL_new_null( );
spc_store->use_certfile = 0;
spc_store->use_certs = sk_X509_new_null( );
spc_store->use_keyfile = 0;
spc_store->use_key = 0;
spc_store->flags = 0;
}
/**
*
*/
void spc_cleanup_x509store(spc_x509store_t *spc_store) {
if (spc_store->cafile) free(spc_store->cafile);
if (spc_store->capath) free(spc_store->capath);
if (spc_store->crlfile) free(spc_store->crlfile);
if (spc_store->use_certfile) free(spc_store->use_certfile);
if (spc_store->use_keyfile) free(spc_store->use_keyfile);
if (spc_store->use_key) EVP_PKEY_free(spc_store->use_key);
sk_X509_free(spc_store->certs);
sk_X509_free(spc_store->crls);
sk_X509_free(spc_store->use_certs);
}
/**
*
*/
X509_STORE *spc_create_x509store(spc_x509store_t *spc_store) {
int i;
X509_STORE *store;
X509_LOOKUP *lookup;
store = X509_STORE_new( );
/**
if (spc_store->callback)
X509_STORE_set_verify_cb_func(store, spc_store->callback);
else
X509_STORE_set_verify_cb_func(store, spc_verify_callback);
**/
if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file( ))))
goto error_exit;
if (!spc_store->cafile) {
printf("no CAFILE \n");
if (!(spc_store->flags & SPC_X509STORE_NO_DEFAULT_CAFILE))
X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT);
} else{
if (!X509_LOOKUP_load_file(lookup, spc_store->cafile,
X509_FILETYPE_PEM))
goto error_exit;
}
if (spc_store->crlfile) {
if (!X509_load_crl_file(lookup, spc_store->crlfile, X509_FILETYPE_PEM))
goto error_exit;
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
X509_V_FLAG_CRL_CHECK_ALL);
}
if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir( ))))
goto error_exit;
if (!spc_store->capath) {
if (!(spc_store->flags & SPC_X509STORE_NO_DEFAULT_CAPATH))
X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT);
} else if (!X509_LOOKUP_add_dir(lookup, spc_store->capath,
X509_FILETYPE_PEM))
goto error_exit;
for (i = 0; i < sk_X509_num(spc_store->certs); i++)
if (!X509_STORE_add_cert(store, sk_X509_value(spc_store->certs, i)))
goto error_exit;
for (i = 0; i < sk_X509_CRL_num(spc_store->crls); i++)
if (!X509_STORE_add_crl(store, sk_X509_CRL_value(spc_store->crls, i)))
goto error_exit;
// printf("success spc_create_x509store\n");
return store;
error_exit:
printf("error_exit spc_create_x509store\n");
if (store) X509_STORE_free(store);
return 0;
}
/**
*
*/
BIO *spc_connect(char *host, int port, int ssl, spc_x509store_t *spc_store,
SSL_CTX **ctx) {
BIO *conn;
/**
SSL *ssl_ptr;
if (ssl) {
if (!(conn = spc_connect_ssl(host, port, spc_store, ctx)))
goto error_exit;
BIO_get_ssl(conn, &ssl_ptr);
if (!spc_verify_cert_hostname(SSL_get_peer_certificate(ssl_ptr),
host))
goto error_exit;
if (SSL_get_verify_result(ssl_ptr) != X509_V_OK)
goto error_exit;
return conn;
}
**/
*ctx = 0;
if (!(conn = BIO_new_connect(host)))
goto error_exit;
BIO_set_conn_int_port(conn, &port);
if (BIO_do_connect(conn) <= 0)
goto error_exit;
return conn;
error_exit:
printf("error_exit connect\n");
if (conn)
BIO_free_all(conn);
return 0;
}
/**
*
*/
spc_ocspresult_t spc_verify_via_ocsp(spc_ocsprequest_t *data) {
BIO *bio = 0;
int rc, reason, ssl, status;
char *host = 0, *path = 0, *port = 0;
SSL_CTX *ctx = 0;
X509_STORE *store = 0;
OCSP_CERTID *id;
OCSP_REQUEST *req = 0;
OCSP_RESPONSE *resp = 0;
OCSP_BASICRESP *basic = 0;
spc_ocspresult_t result;
ASN1_GENERALIZEDTIME *producedAt, *thisUpdate, *nextUpdate;
result = SPC_OCSPRESULT_ERROR_UNKNOWN;
if (!OCSP_parse_url(data->url, &host, &port, &path, &ssl)) {
result = SPC_OCSPRESULT_ERROR_BADOCSPADDRESS;
goto end;
}
if (!(req = OCSP_REQUEST_new( ))) {
result = SPC_OCSPRESULT_ERROR_OUTOFMEMORY;
goto end;
}
//
//Here I guess is where you can add multiple certs" Right now we haev only
one
//
id = OCSP_cert_to_id(0, data->cert, data->issuer);
if (!id || !OCSP_request_add0_id(req, id)) goto end;
//lets do it twice what the heck
//show how to do multiple x509s
// id = OCSP_cert_to_id(0, data->cert, data->issuer);
// if (!id || !OCSP_request_add0_id(req, id)) goto end;
OCSP_request_add1_nonce(req, 0, -1);
/* sign the request */
if (data->sign_cert && data->sign_key &&
!OCSP_request_sign(req, data->sign_cert, data->sign_key,
EVP_sha1( ), 0,
0)) {
result = SPC_OCSPRESULT_ERROR_SIGNFAILURE;
goto end;
}
/* establish a connection to the OCSP responder */
if (!(bio = spc_connect(host, atoi(port), ssl, data->store, &ctx))) {
result = SPC_OCSPRESULT_ERROR_CONNECTFAILURE;
goto end;
}
/* send the request and get a response */
resp = OCSP_sendreq_bio(bio, path, req);
if (resp==NULL)
goto end;
if ((rc = OCSP_response_status(resp)) !=
OCSP_RESPONSE_STATUS_SUCCESSFUL) {
switch (rc) {
case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
result = SPC_OCSPRESULT_ERROR_MALFORMEDREQUEST; break;
case OCSP_RESPONSE_STATUS_INTERNALERROR:
result = SPC_OCSPRESULT_ERROR_INTERNALERROR; break;
case OCSP_RESPONSE_STATUS_TRYLATER:
result = SPC_OCSPRESULT_ERROR_TRYLATER; break;
case OCSP_RESPONSE_STATUS_SIGREQUIRED:
result = SPC_OCSPRESULT_ERROR_SIGREQUIRED; break;
case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
result = SPC_OCSPRESULT_ERROR_UNAUTHORIZED; break;
}
goto end;
}
/* verify the response */
result = SPC_OCSPRESULT_ERROR_INVALIDRESPONSE;
if (!(basic = OCSP_response_get1_basic(resp))) goto end;
if (OCSP_check_nonce(req, basic) <= 0) goto end;
if (data->store && !(store = spc_create_x509store(data->store))) goto
end;
printf("verify signature\n");
//verify signature
if ((rc = OCSP_basic_verify(basic, 0, store, 0)) <= 0) goto end;
if (!OCSP_resp_find_status(basic, id, &status, &reason, &producedAt,
&thisUpdate, &nextUpdate)){
printf("verify signature failed\n");
goto end;
}
if (!OCSP_check_validity(thisUpdate, nextUpdate, data->skew,
data->maxage))
goto end;
/* All done. Set the return code based on the status from the
response. */
if (status == V_OCSP_CERTSTATUS_REVOKED)
result = SPC_OCSPRESULT_CERTIFICATE_REVOKED;
else
result = SPC_OCSPRESULT_CERTIFICATE_VALID;
end:
if (bio) BIO_free_all(bio);
if (host) OPENSSL_free(host);
if (port) OPENSSL_free(port);
if (path) OPENSSL_free(path);
if (req) OCSP_REQUEST_free(req);
if (resp) OCSP_RESPONSE_free(resp);
if (basic) OCSP_BASICRESP_free(basic);
// if (ctx) SSL_CTX_free(ctx);
if (store) X509_STORE_free(store);
return result;
}
void help(){
printf("\nUsage:\n");
printf(" ./OCSPrequest <cert> <issuer root>\n");
printf("eg:\n");
printf(" ./OCSPrequest 1000.pem ./demoCA/cacert.pem\n\n");
exit(0);
}
/**
*
*/
int main(int argc, char **argv){
char *url= "http://127.0.0.1:8082"; //For now our OCSP server
location
char *x509file="./demoCA/newcerts/1000.pem"; //The x509 filename we
want to verify
char *inCAcert="./demoCA/cacert.pem";
X509 *x=NULL;
X509 *issuerRoot=NULL;
switch (argc){
case 1: //defaults
break;
case 3:
x509file= argv[1];
inCAcert= argv[2];
break;
default:
help();
}
printf("\nOCSP URL: %s\n",url);
printf("Cert checking: %s\n",x509file);
printf("Root issuer: %s\n\n",inCAcert);
ERR_load_BIO_strings();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
//Load the X509 file
//
FILE *fp =fopen(x509file, "rb");
if (fp==NULL) {
printf("X509 File not found %s which is to be verified\n",x509file);
return 1;
}
x= PEM_read_X509(fp,&x, NULL, NULL);
if (x==NULL){
fprintf(stderr,"null x509\n");
return 1;
}
fclose(fp);
//Load the X509 file
//
fp =fopen("./demoCA/cacert.pem", "rb");
if (fp==NULL) {
printf("X509 File not found %s which is to be verified\n",x509file);
return 1;
}
issuerRoot= PEM_read_X509(fp,&issuerRoot, NULL, NULL);
if (issuerRoot==NULL){
fprintf(stderr,"null x509 issuer Root\n");
return 1;
}
fclose(fp);
/**
typedef struct {
char *url;
X509 *cert;
X509 *issuer;
spc_x509store_t *store;
X509 *sign_cert;
EVP_PKEY *sign_key;
long skew;
long maxage;
} spc_ocsprequest_t;
**/
spc_ocsprequest_t *req= malloc(sizeof (spc_ocsprequest_t));
req->url = url;
req->cert = x;
req->issuer = issuerRoot;
req->store = malloc(sizeof(spc_x509store_t) );
spc_init_x509store(req->store);
req->store->cafile= inCAcert;
req->sign_cert= NULL; //OCSP request is not optionally signed
req->sign_key = NULL;
req->skew = 5; //5 seconds
req->maxage = 1; //recommended to set to one
spc_ocspresult_t result= spc_verify_via_ocsp(req);
switch (result){
case 0:
printf("Verify result GOOD\n");
break;
case 1:
printf("Verify result REVOKED\n");
default:
printf("ERROR Verify result is %d \n",result);
break;
}
return 0;
}
--
View this message in context:
http://openssl.6102.n7.nabble.com/OSCP-request-tp45835p45889.html
Sent from the OpenSSL - User mailing list archive at Nabble.com.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [email protected]
Automated List Manager [email protected]