retrieve the client certificate chain from an ISAPI request - c

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.

Related

Iterating over an X509 certificate's subject elements and knowing the type

I'd like to iterate over the name entries in a connecting client's certificate and perform some logic.
I found the following example on this page:
X509_NAME *subj = X509_get_subject_name(cert);
for (int i = 0; i < X509_NAME_entry_count(subj); i++) {
X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, i);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
char *str = ASN1_STRING_data(d);
}
As part of my logic I'd like to know which kind of X509_NAME_ENTRY I'm looking at (ideally by it's NID, for instance NID_commonName), but I can't figure out how to extract this information. From looking at OpenSSL's code I see that I can get the ASN1_OBJECT using X509_NAME_ENTRY_get_object, and that has a nid field in it, but it doesn't seem to be exposed so I can't just grab it with ->nid.
Is there any API function I'm missing to get this information?
Another example on this page is this one:
for (;;) {
int lastpos = X509_NAME_get_index_by_NID(subj, NID_commonName, lastpos);
if (lastpos == -1)
break;
X509_NAME_ENTRY *e = X509_NAME_get_entry(subj, lastpos);
/* Do something with e */
}
I'm considering using this approach instead, but I'm wondering if it's less efficient since I have several name entries I'd like to check, and instead of having one run through the subject I'll potentially be moving back and forth (and my server application needs to minimize connection time as much as possible).
To clarify, I don't just need the certificate's common name, I might need other parts of the certificate's subject (based on the server's configuration) so I'd like to be flexible but also go over the subject as cleanly as possible.

Memory leak Using OpenSSL APIs

I am running a DTLS Server which handles more than 500 connections, every time some connections are closed i see there is some RAM memory utilization increases.
I wonder there is a leak in memory from my below approach of Initialize_Sever_Context , create_connexion and close_connexion. The exact code is too big to create actual scenario, so i just outlined the step.
Pls let me know if any extra information is required?
I am using OpenSSL version 1.1.1k on Linux.
//connect_info structure user defined
{
void* sll;
void* bio;
....
}array_of_connections
*connect_info = &array_of_connections;
// global
SSL_CTX* server_ctx;
Initialize_Sever_Context()
{
// server_ctx is global
server_ctx = SSL_CTX_new(DTLS_server_method());
X509_VERIFY_PARAM *local_vpm = X509_VERIFY_PARAM_new()
//setting verify flags, cookie flags and cypher lists etc..
//....
SSL_CTX_set1_param(server_ctx, local_vpm);
}
create_connexion(connect_info)
{
// server_ctx is global
ssl = SSL_new(server_ctx);
bio = BIO_new_dgram(handler, BIO_NOCLOSE);
..
..
SSL_set_bio(ssl, bio, bio);
connect_info->ssl = ssl;
connect_info->bio = bio;
}
handle_closed_connexions()
{
for(conn = 1; conn<MAX_CONN;conn++)
{
close_connexion(connect_info[conn]);
}
}
close_connexion(connect_info)
{
// store prev ssl objects
SLL *local_ssl = connect_info -> ssl;
// make setup ready for the next connexions
// and start listening
create_connexion(connect_info)
// free the previous closed connections
SSL_free(local_ssl);
}
Inside SSL_free we have BIO_free_all(s->rbio), BIO_free_all(s->rbio) and BIO_CTX_free(s->ctx) and finally OPENSSL_free(s)
As far as i understand when we do SSL_free, all the members(pointers) inside SLL object are freed.
But inside OpenSSL non of pointers are set to NULL after free(), so i expect the application to crash.
But my application is working even after the pointers are freed.
Why does not OpenSSL set the pointers to NULL after they are freed or Can i assume that my application is Safe with the above approach?
I have checked posts
1
2 and others, but none of them satisfy my requirement, so i am asking a new question.
Why does not OpenSSL set the pointers to NULL after they are freed or Can i assume that my application is Safe with the above approach?
99.99% of the time, the pointers aren't going to be accessed again, so setting them to NULL serves no purpose. If you do happen to need them set to NULL, then you can set them to NULL.

Convert X509_STORE_load_locations() call to load data from Memory

How can I convert the code below to load the file "cabundle.pem" from memory? The code is used in certificate verification (Source)
const char ca_bundlestr[] = "./cabundle.pem";
ret = X509_STORE_load_locations(store, ca_bundlestr, NULL);`
So what I currently did is put the cabundle.pem in string array and then add the cert to the store but it doesnt work since what I think I need to do is add it to the store using X509_STORE_CTX_trusted_stack but I do not know how to use STACK_OF(X509) I tried searching but I cant find anything.
const char ca_bundle[] = "-----BEGIN CERTIFICATE-----\n"
"MIIImDCCCD2gAwIBAgIRAMch/W0685E2zrArUB/79kUwCgYIKoZIzj0EAwIwgZIx\n"
"MIIImDCCC...............................................AwIwgZIx\n"
"CzAJBgNVB..........................................0ZXIxEDAOBgNV\n"
"-----END CERTIFICATE-----\n";
BIO *bio;
X509 *cert;
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, ca_bundle);
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
X509_STORE_add_cert(store, cert);
So how can I load my string array ca_bundle into a STACK_OF(X509) variable? Or if there is another way to do this please let me know. Thanks
I asked too early. I just found the answer to my question. Since the cabundle.pem contains more than 1 certificate you need to do it in a loop and read the next certificate then add it again to the store. You do not need the X509_STORE_CTX_trusted_stack since adding all the certificates to the store acts the same way as calling X509_STORE_load_locations
while (cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) {
X509_STORE_add_cert(store, cert);
}

QMI SDK start data session

I am using QMI SDK to start data session for the Sierra Wireless card MC7354 and Telus Sim Card. For now I can detect the device and the sim card like getting device info and IMSI number; however, I got some trouble with starting the data session. I follow the instructions in QMI SDK Documents and do the following code:
//set the default profile
ULONG rc3 = SetDefaultProfile(0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
fprintf(stderr, "SetProfile - Return Code: %lu\n", rc3);
//start the session
ULONG technology = 1;
ULONG profile_idx = 1;
struct ssdatasession_params session;
session.action = 1;
session.pTechnology = &technology;
session.pProfileId3GPP = &profile_idx;
session.pProfileId3GPP2 = NULL;
session.ipfamily = 4;
ULONG rc4 = SLQSStartStopDataSession(&session);
fprintf(stderr, "Start Session - Return Code: %lu\n",rc4);
SetDefaultProfile is working fine because it returns me the success code, but for the SLQSStartStopDataSession method, it always gives me the return code "1026", which means
Requested operation would have no effect
Does anyone know where I make mistakes and how should I modify the code? What does this return code mean?
A "No Effect" error in WDS Start Network (the underlying command sent when you use SLQSStartStopDataSession()) actually means that the device is already connected. You likely have configured an automatic connection setup in the modem.

OpenSSL - find error depth in certificate chain

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);
}
}

Resources