ASN1_INTEGER to ASN1_STRING - c

I am using openssl to get data about x509 certificate.
Is there a way to convert ASN1_INTEGER to ASN1_STRING, which can than easily be transformed to char array? Is there a way to convert it to any other human readable format?
EDIT: I'm using openssl compiled for iOS, as I am having the iOS project. Here is the code I am using to extract the serial number from the certificate:
ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
long value = ASN1_INTEGER_get(serial);
NSLog(#"Serial %ld", value);
certificateX509 is a valid X509 object and I have managed to get some other fields from it (issuer name, expiry date and so on)
EDIT 2:
I finally came to a solution, which may not be the most straightforward one:
ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
int n = BN_num_bytes(bnser);
unsigned char outbuf[n];
int bin = BN_bn2bin(bnser, outbuf);
char *hexbuf = (char*) outbuf;
hexBuf then contains characters whose value needs to be read as hex integer in order to retrieve logical values.
I use NSMutableString to create a human readable string:
NSMutableString *str = [[NSMutableString alloc] init];
for (int i=0; i<n; i++) {
NSString *temp = [NSString stringWithFormat:#"%.6x", hexbuf[i]];
[str appendString:[NSString stringWithFormat:#"%# ", temp]];
}
If there is a simpler way, I would really like to know it.

The ascii hex conversion be done more simply using the built in BN_bn2hex(BIGNUM *) function
ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
char *asciiHex = BN_bn2hex(bnser);

One possibility is that you can extract the value of the ASN1_INTEGER as a normal C integer:
#include <openssl/asn1.h>
#include <stdio.h>
int main(int argc, char** argv) {
long value;
ASN1_INTEGER asn1int = {0};
ASN1_INTEGER_set(&asn1int, 42);
value = ASN1_INTEGER_get(&asn1int);
printf("The value is %ld.\n", value);
return 0;
}
Compiled like this:
gcc -Wall -o sploots sploots.c -lcrypto
this produces the output:
The value is 42.
To have the value as a string in an array of char, use snprintf.
I suspect there are also possibilities for using the BIO printing routines to dump the value to a BIO of some sort (perhaps a memory BIO). However, this approach seems simpler.
The way I arrived at this answer is that I looked through the OpenSSL headers for ASN1_INTEGER. After looking around for suitable APIs for a BIO-based solution, I noticed the ASN1_INTEGER_get function.
Looking around in OpenSSL header files is typically the way I learn how to use OpenSSL, since so much of the API is undocumented or incorrectly or incompletely documented.

I finally came to a solution, which may not be the most straightforward one:
ASN1_INTEGER *serial = X509_get_serialNumber(certificateX509);
BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
int n = BN_num_bytes(bnser);
unsigned char outbuf[n];
int bin = BN_bn2bin(bnser, outbuf);
char *hexBuf = (char*) outbuf;
hexBuf then contains characters whose value needs to be read as hex integer in order to retrieve logical values.
I use NSMutableString to create a human readable string:
NSMutableString *str = [[NSMutableString alloc] init];
for (int i=0; i<n; i++) {
NSString *temp = [NSString stringWithFormat:#"%.6x", hexbuf[i]];
[str appendString:[NSString stringWithFormat:#"%# ", temp]];
}

If you just want a readable NSString, BN_bn2dec is more consize than BN_bn2hex or BN_bn2bin.
No need to mess with hex encoding.
Here's my way, in iOS/ObjC, using pod 'OpenSSL-Universal', '1.0.2.10' :
ASN1_INTEGER *serialAsn1 = X509_get_serialNumber(certX509);
BIGNUM *serialBigNumber = ASN1_INTEGER_to_BN(serialAsn1, NULL);
char *serialChar = BN_bn2dec(serialBigNumber);
NSString *serialString = [NSString stringWithCString:(const char *) serialChar
encoding:NSUTF8StringEncoding];
Cheers.

This solution worked for me to get the serial number in hex:
ASN1_INTEGER* serial = X509_get_serialNumber(X509_certificate_ptr);
BIGNUM* bn = ASN1_INTEGER_to_BN(serial, NULL);
if (!bn) {
// log here "Unable to convert ASN1INTEGER to BN";
return "";
}
char* hex = BN_bn2hex(bn);
if (!hex) {
// Log here "Unable to convert BN to hex string";
return "";
}
cout << hex; // this is your serial number. Can be converted using std::to_string()
BN_free(bn);
ASN1_INTEGER_free(serial);
OPENSSL_free(hex);
return serial_number;
Without error checking and memory management the code is basically:
ASN1_INTEGER* serial = X509_get_serialNumber(X509_certificate_ptr);
BIGNUM* bn = ASN1_INTEGER_to_BN(serial, NULL);
char* hex = BN_bn2hex(bn);

Related

ECDSA ciphering with OpenSSL results in memory problem

I'm trying to encrypt a message using the ECDSA algorithm with OpenSSL (1.1.1), but I must be doing something wrong with my pointers, because everytime I run the code, it gives me a different result.
Here's what I do:
create a key using custom curve parameters (with BN_hex2bn);
sign a simple message using ECDSA_do_sign;
split the message into the R and S points (ECDSA_SIG_get0_r and ECDSA_SIG_get0_s);
display the resulting R point.
And the display value is always different, while I expect it to be the same (because same message and same key). I think some memory is deallocated somewhere, giving me a pointer to invalid data, but I'm not sure about it; I have checked:
the keys are ok, and they are valid according to EC_KEY_check_key;
the two variables s and r are already wrong, hence it doesn't come from BN_bn2bin.
Here is my code if you want to give a try:
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/ecdsa.h>
#include <openssl/buffer.h>
int main(void) {
ECDSA_SIG *sig;
EC_KEY *eckey;
BIGNUM *priv_key = BN_new();
BIGNUM *x_key = BN_new();
BIGNUM *y_key = BN_new();
const char digest[] = "Hello, world!";
eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
// Set predefined keys
BN_hex2bn(&priv_key, "8e9b109e719098bf980487df1f5d77e9cb29606ebed2263b5f57c213df84f4b2");
BN_hex2bn(&x_key, "7fcdce2770f6c45d4183cbee6fdb4b7b580733357be9ef13bacf6e3c7bd15445");
BN_hex2bn(&y_key, "c7f144cd1bbd9b7e872cdfedb9eeb9f4b3695d6ea90b24ad8a4623288588e5ad");
EC_KEY_set_private_key(eckey, priv_key);
EC_KEY_set_public_key_affine_coordinates(eckey, x_key, y_key);
sig = ECDSA_do_sign(digest, 32, eckey);
// Get the resulting point
const BIGNUM *r = ECDSA_SIG_get0_r(sig);
const BIGNUM *s = ECDSA_SIG_get0_s(sig);
unsigned char rc[256];
unsigned char sc[256];
BN_bn2bin(r, rc);
BN_bn2bin(s, sc);
// Print the result: some memory problem...
for(int i = 0; rc[i] != 0; i++) {
printf("%d ", rc[i]);
}
return 0;
}
Do no forget to link the libraries when you compile it: gcc -g -o main main.c -lssl -lcrypto.

Segmentation fault with generating an RSA and saving in ASN.1/DER?

#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#define RSA_LEN 2048
#define RSA_FACTOR 65537
int genRSA2048(unsigned char **pub,unsigned int *pub_l,unsigned char **priv,unsigned int *priv_l){
RSA *pRSA = NULL;
pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);
if (pRSA){
pub_l = malloc(sizeof(pub_l));
*pub_l = i2d_RSAPublicKey(pRSA,pub);
priv_l = malloc(sizeof(priv_l));
*priv_l = i2d_RSAPrivateKey(pRSA,priv);
return 0;
} else {
return 1;
}
}
int main(){
unsigned char *pub = NULL;
unsigned int publ;
unsigned char *priv = NULL;
unsigned int privl;
genRSA2048(&pub,&publ,&priv,&privl);
RSA *privrsa = NULL;
d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);
RSA *pubrsa = NULL;
d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);
unsigned char * data ="01234567890123456789012345678912";
unsigned char encrypted[256];
unsigned char decrypted[32];
int len = RSA_private_encrypt(32,data,encrypted,privrsa,RSA_PKCS1_PADDING);
RSA_public_decrypt(len,encrypted,decrypted,pubrsa,RSA_PKCS1_PADDING);
}
I've tried to find the bug by checking with gdb but as being fairly new to C I haven't find any clue to tell me what is happening but I believe it's an allocation problem, however according to the d2i_RSAPrivateKey and similar, they're supposed to allocate the space by itself.
Any help would be greatly appreciated.
compiled as cc foo.c -lcrypto
This is the follow up of this question:
Generate RSA public/private key with OpenSSL?
As I reference I used #WhozCraig example in the comments, which can be found here, even when it's quite different, it was a lot of help.
http://coliru.stacked-crooked.com/a/ae64a70076436165
pub_l = malloc(sizeof(pub_l)); is simply not needed. Nor is priv_l = malloc(sizeof(priv_l));. Remove them both from your function.
You should be populating your out-parameters; instead you're throwing out the caller's provided addresses to populate and (a) populating your own, then (b) leaking the memory you just allocated.
The result is the caller's privl and publ are untouched and thus the decoding back to RSA is dysfunctional, as both values are indeterminate.
pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);
I think this is wrong. I know you are supposed to use RSA_generate_key_ex, and I think it needs a BIGNUM, not an integer. You should have gotten a warning. See RSA_generate_key(3) for details.
Your code should look something like:
BIGNUM* exp = BN_new();
ASSERT(exp != NULL);
int rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);
RSA* rsa = RSA_new();
ASSERT(rsa != NULL);
rc = RSA_generate_key_ex(rsa, 2048, exp, NULL);
ASSERT(rc == 1);
Be sure to call BN_free on the BIGNUM, and RSA_free on the RSA pointer.
RSA *privrsa = NULL;
d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);
RSA *pubrsa = NULL;
d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);
For this, it looks like you are trying to separate the public key and private key. For that, use RSAPublicKey_dup and RSAPrivateKey_dup. See Separating public and private keys from RSA keypair variable.
Its not clear to me what you are trying to do with the following. You should state what you are trying to do...
pub_l = malloc(sizeof(pub_l));
*pub_l = i2d_RSAPublicKey(pRSA,pub);
priv_l = malloc(sizeof(priv_l));
*priv_l = i2d_RSAPrivateKey(pRSA,priv);
I'm just guessing, but I'm going to say its all wrong. sizeof(priv_l) is the size of a pointer, so its 4 or 8 bytes. You're also overwriting the pointer passed in by the caller...
Also see OpenSSL's rsautl cannot load public key created with PEM_write_RSAPublicKey. It talks about saving the keys with SubjectPublicKeyInfo and PrivateKeyInfo in both ASN.1/DER and PEM formats.
By writing the {Public|Private}KeyInfo, the OID gets written to the key. That's important for interop. You also use the RSA* (and even an EVP_PKEY*), and not byte arrays.

PEM_read_RSAPrivateKey: Getting RSA key public modulus and exponent

I'm using PEM_read_RSAPrivateKey function in this way:
void test(void)
{
RSA * privateKey = NULL;
FILE * fp;
if(NULL != (fp= fopen("./my_file.key", "r")) )
{
privateKey=PEM_read_RSAPrivateKey(fp,NULL,NULL,NULL);
if(privateKey==NULL)
{
printf("\n\tCould NOT read RSA private key file");
}
else
{
printf("\n\tRSA structure filled");
}
// This is working OK and privateKey is NOT NULL
}
}
Then, I try to retrieve modulus and public exponent to fill them into a personal structure:
struct
{
unsigned char modulus[256];
unsigned char pub_exp[8];
} s;
But all accesses I tried (I tried a lot) to privateKey->n will result in a segmentation fault.
for example:
unsigned char modulus [2048];
unsigned char exp[2048];
BN_bn2bin(privateKey->n, modulus); // Segmentation fault results from this call
So my question is: how to copy modulus or public exponent from RSA structure to my structure "s" fields?
May someone help about this?
Many thanks,
Regards,
Sylvain
how to copy modulus or public exponent from RSA structure
int req = BN_num_bytes(rsa->n);
assert(rc > 0);
unsigned char* buff = malloc(req);
assert(buff != NULL);
int rc = BN_bn2bin(rsa->n, buff);
assert(req == rc);
Be wary of trying to copy the byte buffers into fixed sized arrays. Someone might come along and get you to copy a 4096-bit modulus into your 2048-bit array.
From OpenSSL 1.1.0 many structures were made opaque and you can no longer do things like look directly at the fields in a struct.
You should use the provided accessor functions instead. Here you can find more infos: https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
Acces rsa->n in OpenSSL 1.1.0:
RSA *pRsa;
BIGNUM *n;
FILE *pFile = fopen("private.key","r");
pRsa = PEM_read_RSAPrivateKey(pFile, NULL, NULL, password);
RSA_get0_key(pRSA, &n, NULL,NULL);
BN_print_fp(stdout, n);

C: implementing a Sha512 encryption with crypt(3)

As the title is saying I want to implement a simple Sha512 encryption with the C function crypt(3).
I have pretty much copied the examplecode from the GNU, even though I know the salt calculation isn`t very good. Also I changed the $1$ to the $6$, since the manpage of crypt says that this would create an SHA512 hash.
Anyway the output seems very strange to me, so I am asking if there is anything wrong with my code:
This is pretty much the function:
static char* hashStr(char *str) {
unsigned long seed[2];
char salt[] = "$6$........";
const char *const seedchars =
"./0123456789ABCDEFGHIJKLMNOPQRST"
"UVWXYZabcdefghijklmnopqrstuvwxyz";
seed[0] = time(NULL);
seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000);
// Turn it into printable characters from `seedchars'.
for (int i = 0; i < 8; i++) {
salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f];
}
return crypt(str, salt);
}
Heres some output:
Bro -> $6$9AcWGmwG$5faOmA7QpXQ/MMmbFAT085HraONeaMYlTcBg09WmQUpSI.PkcrcDQiXCetyjuIK3sr3H5cIFyxHD.fywr9UfY/
Homie -> $6$BAcWGnwG$KUPLOdpa8QgF.cVljBXYl62lL9zejDW/ZWENUoC90jO4NinNc1Itk7Z1Zo3myogmHR/YPwoc2cqfjBL0cf.Ht0
hey -> $6$IAcWGowG$47WGhO6Hco9DOc0rnxu/KEttLvjv4wH6vJX8qj6hALr0Wa1/YQb0JETEcRgpe9.cPvwOBjQduLZn17gwSXM86.
What makes me wonder if the output is legit is especially that theres this &6& at the beginning every time.
As you can see here crypt(3) return:
$id$salt$encrypted
That's why you get $6$8chars$...

parsing/matching string occurrence in C

I have the following string:
const char *str = "\"This is just some random text\" 130 28194 \"Some other string\" \"String 3\""
I would like to get the the integer 28194 of course the integer varies, so I can't do strstr("20194").
So I was wondering what would be a good way to get that part of the string?
I was thinking to use #include <regex.h> which I already have a procedure to match regexp's but not sure how the regexp in C will look like using the POSIX style notation. [:alpha:]+[:digit:] and if performance will be an issue. Or will it be better using strchr,strstr?
Any ideas will be appreciate it
If you want to use regex, you can use:
const char *str = "\"This is just some random text\" 130 28194 \"Some other string\" \"String 3\"";
regex_t re;
regmatch_t matches[2];
int comp_ret = regcomp(&re, "([[:digit:]]+) \"", REG_EXTENDED);
if(comp_ret)
{
// Error occured. See regex.h
}
if(!regexec(&re, str, 2, matches, 0))
{
long long result = strtoll(str + matches[1].rm_so, NULL, 10);
printf("%lld\n", result);
}
else
{
// Didn't match
}
regfree(&re);
You're correct that there are other approaches.
EDIT: Changed to use non-optional repetition and show more error checking.

Resources