OpenSSL - find error depth in certificate chain - c

I am writing a C program to retrieve and verify an x509 certificate chain using OpenSSL. This is my first time programming in C and am relying heavily on the tutorial at http://www.ibm.com/developerworks/linux/library/l-openssl/
I am able to retrieve any error code from the connection using the code below:
if (SSL_get_verify_result(ssl) != X509_V_OK)
{
printf("\nError verifying certificate\n");
fprintf(stderr, "Error Code: %lu\n", SSL_get_verify_result(ssl));
}
however I also need to know which certificate is the offending one. Is there are way to determine the chain depth of the error like the command line s_client? Any example code would be greatly appreciated.

I found my answer in "Network Security with OpenSSL" by Chandra, Messier and Viega.
It uses SSL_CTX_set_verify to designate a callback function that gets run after the verification routine for each certificate in the chain.
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
int verify_callback(int ok, X509_STORE_CTX * store)
{
if (!ok) //if this particular cert had an error
{
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
}
}

Related

libssh: ssh_is_host_known called without cryptographic context

I was trying to include SSH communication into my program using libssh 0.7.0. I followed the tutorial to create a simple connection to a remote machine but I came across this error:
[2016/10/26 16:38:56.280261, 1] ssh_is_server_known: ssh_is_host_known called without cryptographic context
After searching the source code of the library and its documentation, I didn't find anything related to this "lack" of cryptographic context that could help solving the issue.
Here's the code I'm trying to execute (it's part of a function; IP address and user are not the actual ones):
ssh_session session;
int verbosity = SSH_LOG_PROTOCOL;
int port = 22;
int state;
ssh_init();
session = ssh_new();
if (session == NULL){
printf("Failed to create SSH session\n"); return NULL;
}
ssh_options_set(session, SSH_OPTIONS_HOST, "111.111.111.111");
ssh_options_set(session, SSH_OPTIONS_USER, "user");
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
state = ssh_is_server_known(session);
if(state != SSH_SERVER_KNOWN_OK){
printf("SSH Server is not known\n");
}
(I tried to execute this section without calling ssh_init() but the error occurred on both cases).
According to the tour (tutorial) on official page, you need to connect to the server, before verifying that the server is known (the server needs to send you its host key). Therefore add a
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error connecting to localhost: %s\n",
ssh_get_error(my_ssh_session));
exit(-1);
}
before checking ssh_is_server_known().

Erratic openssl/rsa behaviour: RSA_EAY_PRIVATE_DECRYPT:padding check failed

I have written a program that runs permanently using <openssl/rsa> C library.
It basically decrypts a password given in argument. The problem is that sometimes it works flawlessly, and some other times it fails (with the same pubkey/privkey/password, returning this error:
message: error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
Has anyone ever experienced that?
Why this kind of error is returned, generally?
Some more details
It retrieves the private key at the initialisation of the program with the following:
#define PRIVFILE "<correct-path>/privkey.pem"
EVP_PKEY *privKey;
int size_key;
FILE *fp = fopen(PRIVFILE, "r");
if (!fp)
{
<logs>
return -1;
}
PEM_read_PrivateKey(fp, &privKey, 0, NULL);
fclose (fp);
if (privKey == NULL)
{
ERR_print_errors_fp (stderr);
return -1;
}
size_key = EVP_PKEY_size(privKey);
Later, during a listening loop, a method call the private decryption algorithm
int len_enc = size_key;
unsigned char* enc_pw;
unsigned char* dec_pw;
int len_dec = 8;
char* err = malloc(130);
enc_pw = malloc(len_enc);
dec_pw = malloc(len_dec);
memset(enc_pw, 0, len_enc);
memset(dec_pw, 0, len_dec);
memcpy(enc_pw, value, len_enc); //value being the raw ciphered data to decrypt
ERR_load_crypto_strings();
if (RSA_private_decrypt(len_enc, enc_pw, dec_pw, privKey->pkey.rsa,RSA_PKCS1_OAEP_PADDING) == -1)
{
ERR_error_string(ERR_get_error(), err);
radlog(L_ERR, "message: %s", err);
}
free(enc_pw);
free(dec_pw);
free(err);
I have done encryption on the data with perl using Crypt::OpenSSL::RSA:
my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key( $key_string);
my $ciphertext = $rsa_pub->encrypt( $plaintext);
There is some base64 encoding/decoding that i didn't mention to make it a little bit shorter. The problem does not come from that.
private key and public key are generated with openssl genrsa:
openssl genrsa -out privkey.pem 1024 and openssl rsa -in privkey.pem -pubout > pubkey.pub
It seems to work for some time, but occasionally (during a peak of request, if that matters) i get these errors for ciphered data that seemed valid before:
message: error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
Is it a multi threaded application?
I was getting the same problem yesterday and, in my case, it was related to more than one thread using the key (one for decript and many others for encript). The problem was solved protecting the key with a mutex semaphore.
The service is up and stable since yesterday.

How to verify a X509 certificate in C

I have a certificate in X509 format. this a input parameters in a function.
What I would like to do is to verify the validity of the certificate.
How can it be done?
X509_verify_cert();
I found this function, but this does not accept a X509* certificate, it accepts X509_store and I only have a X509.
Thanks
best regards.
I am here just to post my answer as I found it with the above comments.
I had no certificate chain, so in the work I'm doing I only have a certificate generated by me programatically. I wanted to check the validity of it, so I created the following function, which checks the certificate against itself in other to verify the validity of it.
void check_certificate_validaty(X509* certificate)
{
int status;
X509_STORE_CTX *ctx;
ctx = X509_STORE_CTX_new();
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, certificate);
X509_STORE_CTX_init(ctx, store, certificate, NULL);
status = X509_verify_cert(ctx);
if(status == 1)
{
printf("Certificate verified ok\n");
}else
{
printf("%s\n", X509_verify_cert_error_string(ctx->error));
}
}
Hope this helps someone :)
See the documentation here.
You need to create a certificate store using X509_STORE_CTX_new.
Then add certificate chain using X509_STORE_CTX_set_chain. Add trusted root certificate using X509_STORE_CTX_trusted_stack.
Finally add certificate to be verified using X509_STORE_CTX_set_cert.
After that call X509_verify_cert.
I hope this will help you to start on this.
To verify a certificate signature, you need the public key of an issuer certificate. This issuer certificate's signature is verified with another issuing certificate (or trusted root certificate). Thus if a certificate's signature verifies all the way up a chain to a trusted root, then that certificate is considered trusted.
Self-signed certificates' signatures are verified using their own public key, like the example below:
int verify_cert(const char* pem_c_str)
{
BIO *bio_mem = BIO_new(BIO_s_mem());
BIO_puts(bio_mem, pem_c_str);
X509 * x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
EVP_PKEY *pkey=X509_get_pubkey(x509);
int r= X509_verify(x509, pkey);
EVP_PKEY_free(pkey);
BIO_free(bio_mem);
X509_free(x509);
return r;
}
from: http://www.zedwood.com/article/openssl-c-verify-self-signed-certificate-signature

C_Login fails in PKCS11 in C

Simple issue, but i don't know how to unlock USB Token(epass2003) ,I have try to read PKCS 11 but have no idea how to implement C_Login function for execution in c ,when i am using command line tool (Linux)to do that token is working perfectly fine but with c its not working I have used user type as CKU_USER, Can anyone have knowledge about this, please help
you have to check the return values from the PKCS functions to see if there has been any errors. Try this way and see what happen. If the return code from C_login() is CKR_PIN_LOCKED, then it is clear that you should unlock your card.
CK_RV ret;
ret = C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session);
if (ret != CKR_OK){
error_message(ret);
return;
}
readPIN("Intro PIN: ", pin, 4);
ret = (f_C_Login)(hSession,CKU_USER, (unsigned char *) pin,strlen(pin));
if (ret != CKR_OK){
closeSessions(slot);
error_message(ret);
return;
}
A token can get locked due to a certain number of failed login (for TrustKey it is 10). There are provider specific utilities to unlock tokens. You could check Feitian site. There is some pointer to this kind of problem in Gooze forum (though not exactly). Your problem looks quite like a token lock problem.

retrieve the client certificate chain from an ISAPI request

I would like to retrieve the entire client certificate chain from a request in ISAPI.
I already succeeded to get the first certificate in the client's certificate chain by invoking the code below:
LPEXTENSION_CONTROL_BLOCK ecb_;
...
CERT_CONTEXT_EX cce;
memset(&cce, 0, sizeof(CERT_CONTEXT_EX));
char certbuf[64*1024];
cce.cbAllocated = sizeof(certbuf);
cce.CertContext.pbCertEncoded = (BYTE *) &certbuf;
ecb_->ServerSupportFunction(ecb_->ConnID, HSE_REQ_GET_CERT_INFO_EX, &cce, 0, 0)
However, I did not find out how to retrieve the rest of the certificate chain from this CERT_CONTEXT_EX struct.
I just came across this old question. I'm sorry I didn't see it sooner.
Many years ago I wrote a sample that shows how do do this using CAPICOM. Unfortunately CAPICOM is being phased out by Microsoft, though it still works.
I found the old isapiCertPolicy sample on Koders:
http://www.koders.com/cpp/fid977D79B2C51AD2423E4F57B6B36C3806F167CF79.aspx
Here are the relevant code fragments:
#import "capicom.dll"
char CertificateBuf[8192];
CERT_CONTEXT_EX ccex;
ccex.cbAllocated = sizeof(CertificateBuf);
ccex.CertContext.pbCertEncoded = (BYTE*)CertificateBuf;
ccex.dwCertificateFlags = 0;
DWORD dwSize = sizeof(ccex);
fOk = pCtxt->ServerSupportFunction(
(enum SF_REQ_TYPE)HSE_REQ_GET_CERT_INFO_EX,
(LPVOID)&ccex,
&dwSize,
NULL);
_bstr_t bstrCert(
SysAllocStringLen(
(OLECHAR * )ccex.CertContext.pbCertEncoded,
(ccex.CertContext.cbCertEncoded+1)/2),
FALSE);
CAPICOM::ICertificate2Ptr Cert(__uuidof(CAPICOM::Certificate));
Cert->Import(bstrCert);
CAPICOM::IChainPtr Chain(__uuidof(CAPICOM::Chain));
BOOL fOk = Chain->Build(Cert);
CAPICOM::ICertificatesPtr Certs(NULL);
Certs = Chain->Certificates;
CAPICOM::ICertificate2Ptr ParentCert(Certs->Item[2])
The Chain object builds the certificate chain. If you can't use CAPICOM, you can get the certificate chain using the Crypto API's CertGetCertificateChain function, but it's more work.

Resources