openssl: how to read a .crt file..? - c

I want to read the certifi.crt file using OpenSSL API (not in commands). I have no idea how to do that. If any one knows, please help me. Thank you.
If you give example code that will be very helpful.

If the ".crt" extension refers to a PEM text file (begins with -----BEGIN CERTIFICATE----- followed by base64), then get started in the OpenSSL docs here.
Here is some code to get you started (link with ssl, e.g. g++ a.c -lssl):
#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
int main(int argc, char** argv)
{
FILE* f = fopen("certifi.crt", "r");
if (f != NULL)
{
X509* x509 = PEM_read_X509(f, NULL, NULL, NULL);
if (x509 != NULL)
{
char* p = X509_NAME_oneline(X509_get_issuer_name(x509), 0, 0);
if (p)
{
printf("NAME: %s\n", p);
OPENSSL_free(p);
}
X509_free(x509);
}
}
return 0;
}

Related

generate RSA keypair with openssl

I'm trying to generate set of RSA keys using EVP_RSA_gen interface from openssl/evp.h.
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/err.h>
int main() {
EVP_PKEY *pkey = NULL;
pkey = EVP_RSA_gen(4096);
if (pkey == NULL){
ERR_print_errors_fp(stderr);
printf("Key generation failed.\n");
}
size_t keyLen;
if (EVP_PKEY_get_raw_public_key(pkey, NULL, &keyLen) != 1) {
ERR_print_errors_fp(stderr);
printf("Key extraction failed.\n");
}
return 0;
}
However, when I try to get the size of a raw public key using EVP_PKEY_get_raw_public_key as described here, it fails and the Key extraction failed gets printed. ERR_print_errors_fp doesn't output any message.
What am I doing wrong? It seems there are no mistakes in the code.

How to get device name on which a file is located from its path in c?

Let's say I have a file in Linux with this path:
/path/to/file/test.mp3
I want to know the path to its device. For example I want to get something like:
/dev/sdb1
How do I do this with the C programming language?
I know the terminal command to do it, but I need C functions that will do the job.
EDIT:
I have read this question before asking mine. It doesn't concretly mention code in C, it's more related to bash than to the C language.
Thanks.
You need to use stat on the file path, and get the device ID st_dev and match that to a device in /proc/partitions
Read this for how to interpret st_dev: https://web.archive.org/web/20171013194110/http://www.makelinux.net:80/ldd3/chp-3-sect-2
I just needed that inside a program I am writing...
So instead of running "df" and parsing the output, I wrote it from scratch.
Feel free to contribute!
To answer the question:
You first find the device inode using stat() then iterate and parse /proc/self/mountinfo to find the inode and get the device name.
/*
Get physical device from file or directory name.
By Zibri <zibri AT zibri DOT org>
https://github.com/Zibri/get_device
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libgen.h>
int get_device(char *name)
{
struct stat fs;
if (stat(name, &fs) < 0) {
fprintf(stderr, "%s: No such file or directory\n", name);
return -1;
}
FILE *f;
char sline[256];
char minmaj[128];
sprintf(minmaj, "%d:%d ", (int) fs.st_dev >> 8, (int) fs.st_dev & 0xff);
f = fopen("/proc/self/mountinfo", "r");
if (f == NULL) {
fprintf(stderr, "Failed to open /proc/self/mountinfo\n");
exit(-1);
}
while (fgets(sline, 256, f)) {
char *token;
char *where;
token = strtok(sline, "-");
where = strstr(token, minmaj);
if (where) {
token = strtok(NULL, " -:");
token = strtok(NULL, " -:");
printf("%s\n", token);
break;
}
}
fclose(f);
return -1;
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage:\n%s FILE OR DIRECTORY...\n", basename(argv[0]));
return -1;
}
get_device(argv[1]);
return 0;
}
output is just the device name.
Example:
$ gcc -O3 getdevice.c -o gd -Wall
$ ./gd .
/dev/sda4
$ ./gd /mnt/C
/dev/sda3
$ ./gd /mnt/D
/dev/sdb1
$
Use this command to print the partition path:
df -P <pathname> | awk 'END{print $1}'

RSA Public Key Conversion with just Modulus

I received an RSA-2048 bit public key (256 bytes) as a file which contains just those 256 bytes. Which function in SSL enables me to load this key as an RSA structure so I can convert it to another format? This is in C code using openssl source.
I think it's the DER format, but I'm not 100% certain.
I just put this together and it seems to work correctly:
https://github.com/JonathonReinhart/rawrsa
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
static const char* appname;
static void print_bn(const char *what, const BIGNUM *bn)
{
#ifdef DEBUG
char *str = BN_bn2hex(bn);
printf("%s (hex): %s\n", what, str);
OPENSSL_free(str);
#endif
}
static void usage(void)
{
fprintf(stderr, "Usage: %s modulus-file exponent\n", appname);
}
#define err(fmt, ...) \
fprintf(stderr, "%s: " fmt, appname, ##__VA_ARGS__)
int main(int argc, char *argv[])
{
appname = basename(argv[0]);
if (argc < 3) {
usage();
exit(1);
}
const char *modfile = argv[1];
const char *expstr = argv[2];
/* Read modulus */
FILE *mf = fopen(modfile, "rb");
if (!mf) {
err("Failed to open \"%s\": %m\n", modfile);
return 1;
}
unsigned char buf[256];
if (fread(buf, sizeof(buf), 1, mf) != 1) {
err("Failed to read %zu bytes of modulus\n", sizeof(buf));
return 1;
}
fclose(mf);
BIGNUM *mod = BN_bin2bn(buf, sizeof(buf), NULL);
if (!mod) {
err("BN_bin2bn() failed\n");
return 1;
}
print_bn("Modulus", mod);
/* Parse exponent */
BIGNUM *exp = NULL;
if (BN_dec2bn(&exp, expstr) == 0) {
err("BN_dec2bn() failed\n");
return 1;
}
print_bn("Exponent", exp);
/* Create RSA key */
RSA *rsa = RSA_new();
if (!rsa) {
err("RSA_new() failed\n");
return 1;
}
rsa->e = exp;
rsa->n = mod;
/* Write PEM-encoded RSA public key to stdout */
if (!PEM_write_RSAPublicKey(stdout, rsa)) {
err("PEM_write_RSAPublicKey() failed\n");
return 1;
}
return 0;
}
I use BN_bin2bn to create an OpenSSL bignum from raw binary data from a file. This is where we load your 256-byte modulus.
Then, I use BN_dec2bn to create a bignum from the exponent provided on the command line.
Next, I create an RSA object with RSA_new, and set the public exponent (rsa->e) and modulus (rsa->n).
Finally, I write the RSA public key to a PEM file with PEM_write_RSAPublicKey.
Example:
$ scons -Q
gcc -o main.o -c -Wall -Werror -g main.c
gcc -o rawrsa main.o -lcrypto
$ ./rawrsa key.bin 65537
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA9cFHSTQ6h1Ls/vx7B+V/84XVlLxUU1dU1mEr9ROAqWrZtfasvx2E
21lbva+AdJ/B4u6fGVhCEMgekXsRB65CqZfwL3DFL6tqam6GvrOyvZgAlQKrA54w
DaKMT8Kfg2I2K9W/HCkCOHczhuHhjFmeiV9BuQgpmcPcNz6UXBwU05d3g6oM/X4m
lEhEsaH4bqo1qsMX6jp6WnsR13GEfsYoYVmHgEbnKJyGpsoRVW6HQXLHvef9XLEJ
v9n7nLdHToya75svxJ3v9JugD3n6PiC48085/FWb9980o4hmG9iW5rehm4Dlui8c
TDnHkQSrvi9WLlZ+S8hdtwDRN/pVVTjgPAIDAQAB
-----END RSA PUBLIC KEY-----

Extract pem certificate information programmatically using openssl

Using the openssl command line is possible to extract, in a human readable mode, all the information contained in a .pem certificate; that is:
openssl x509 -noout -in <MyCertificate>.pem -text
What are the suitable steps in order to extract this information using the openssl API?
The X509_print_ex family of functions is your answer.
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
int main(int argc, char **argv)
{
X509 *x509;
BIO *i = BIO_new(BIO_s_file());
BIO *o = BIO_new_fp(stdout,BIO_NOCLOSE);
if((argc < 2) ||
(BIO_read_filename(i, argv[1]) <= 0) ||
((x509 = PEM_read_bio_X509_AUX(i, NULL, NULL, NULL)) == NULL)) {
return -1;
}
X509_print_ex(o, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
}
As additional information related to this question, in case of having a certificate with the DER format instead of PEM; it is also possible to extract the information in a human readable mode using the following code:
//Assuming that the DER certificate binary information is stored in
//a byte array (unsigned char) called "pData" whose size is "lenData"
X509* x509;
BIO* input = BIO_new_mem_buf((void*)pData, lenData);
//d2i_X509_bio: Decodes the binary DER certificate
//and parses it to a X509 structure
x509 = d2i_X509_bio(input, NULL);
if (x509 == NULL)
{
//Error in d2i_X509_bio
}
else
{
//"certificateFile" is the full path file
//where to store the certificate information
//in a human readable mode (instead of stdout)
FILE* fd = fopen(certificateFile, "w+");
BIO* output = BIO_new_fp(fd, BIO_NOCLOSE);
X509_print_ex(output, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
fclose(fd);
BIO_free_all(output);
}
BIO_free_all(input);

How to verify the password of a pkcs#12 certificate (.PXF) with openssl C API?

I have an .pxf (AFAIK PKCS#12) certificate. How can I confirm a given password for this certificate using the openssl C API?
One approach to finding answers like this is to find an OpenSSL utility that performs the same functionality as what you are trying to do. In this case, you can use the pkcs12 utility that comes with OpenSSL to verify the password.
The command to verify a pfx file is the following:
openssl pkcs12 -in mypfx.pfx -noout
With that information, you can then look at its source code ({openssl_src}/apps/pkcs12.c) to see how they do it.
The source code shows that it calls PKCS12_verify_mac to verify the password. First to verify that there is no password:
if( PKCS12_verify_mac(p12, NULL, 0) )
{
printf("PKCS12 has no password.\n");
}
And then if there is a password, verify it by passing it as an argument:
if( PKCS12_verify_mac(p12, password, -1) )
{
printf("PKCS12 password matches.\n");
}
OpenSSL also has demos for working with PKCS12 in openssl/demos/pkcs12. The pkread.c demo provides an example for parsing a pfx file with a password.
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit(1);
}
Full example, compiled with gcc -std=c99 verifypfx.c -o verifypfx -lcrypto:
#include <stdio.h>
#include <errno.h>
#include <openssl/pkcs12.h>
#include <openssl/err.h>
int main(int argc, char *argv[])
{
const char *password = "mypassword";
PKCS12 *p12;
// Load the pfx file.
FILE *fp = fopen("mypfx.pfx", "rb");
if( fp == NULL ) { perror("fopen"); return 1; }
p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
OpenSSL_add_all_algorithms();
ERR_load_PKCS12_strings();
if( p12 == NULL ) { ERR_print_errors_fp(stderr); exit(1); }
// Note: No password is not the same as zero-length password. Check for both.
if( PKCS12_verify_mac(p12, NULL, 0) )
{
printf("PKCS12 has no password.\n");
}
else if( PKCS12_verify_mac(p12, password, -1) )
{
printf("PKCS12 password matches.\n");
}
else
{
printf("Password not correct.\n");
}
return 0;
}
Use PKCS12_verify_mac(). eg.
FILE* f = fopen("myfile.pfx", "rb");
PKCS12* p12 = d2i_PKCS12_fp(f, NULL);
fclose(f);
if (!PKCS12_verify_mac(p12, (char*)"mypassword", strlen("mypassword")))
{
// handle failure
}

Resources