I am using following code (simplified little bit) to get certificate string from X509 structure. Basically PEM_write_bio_X509 function.
X509 *certificate...
....
BIO *bio = BIO_new(BIO_s_mem()), BIO_vfree);
if (!bio || !PEM_write_bio_X509(bio, certificate)) {
// error handling
}
size_t keylen = BIO_pending(bio);
unique_ptr<char[]> key(new char[keylen]);
int len = BIO_read(bio, key.get(), (int)keylen);
if (len <= 0) {
// error handling
}
string result = string(key.get(), len);
The result is correctly something like
-----BEGIN CERTIFICATE-----
MIIFLTCCAxUCCQDrAnFYOmsVkzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJB
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
-----END CERTIFICATE-----
Is there any way (without converting it manually myself later) to get it directly from OpenSSL as one line string without header lines? Something like:
MIIFLTCCAxUCCQDrAnFYOmsVkzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
There are two OpenSSL functions that can help you to achieve this
PEM_read_bio() can read your PEM-formatted certificate file (or any PEM-formatted file for that matter) and split it into its header and data.
You are subsequently interested in the contents obtained in the data pointer, encoded as base64 in a long string. EVP_EncodeBlock() can give you that by giving it those contents as its second parameter.
A rough outline of your code :
ret = PEM_read_bio(bio, &name, &header, &data, &len);
if (!ret) {
// error
}
// Make sure b64block is allocated to contain at least
// 4*ceil(len/3) + 1 bytes
blockLen = EVP_EncodeBlock(b64block, data, len);
// b64block now contains the desired base64 in blockLen relevant bytes,
// plus a null-character
// Don't forget to OPENSSL_free the name, header and data pointers
Related
I working on little ECC crypto problem.
The goal is to write a program in C or bash, which will take as input a hash composed of 128 characters in hexadecimal
(Example: 8A9A35145C4EA5260DF9972C804FE2D3F9F3D7A2AC01A6BEB21C82BB30957B3952273AC9166B90C1207347A925780F84A1D2359E7AA05201C674D2B9746FCA07)
and which will generate from the input hash a private key and a public key of type Elliptic Curve and display the key pair generated.
Can someone clarify for me the problem. I can't understand why we need a hash(or any string) to generate a pair key, as I found In many online solution like this one ther's no need to give a hash. Maybe is it a parphase ? Maybe It's the curve key or somthing similar.
I think all we need is to do something like this for the private key:
openssl ecparam -genkey -noout -out myprivatekey.pem
and for the public key generation:
openssl -ec -in myprivatekey.pem -pubout -out mypublickey.pem
The question is : why we need an input a hash composed of 128 to generate our pair keys? Is it a passphrase for security reason? how made the trick with openssl ?
You could use a hash if you've got some kind of input binary value which you need to convert to a key.
You can use a hash as input for a private key. To convert it you should first convert it to a number and then perform a calculation modulo n on it, where n is the order of the ECC domain parameters. The resulting value can be called s Then you can calculate the public key out of it by performing s * G, i.e. point multiplication with the base point.
OpenSSL is not a low level crypto library, so you'd have to program it, possibly using the OpenSSL API and the BN (big number) library that comes with it. It is not that tricky, but if you're still talking about 128 characters instead of 64 bytes then you may have a lot of learning to do.
In fact this is my own code, you can improve it and edit the solution bellow:
// gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
int main()
{
EC_KEY *eckey = NULL;
EC_POINT *pub_key = NULL;
const EC_GROUP *group = NULL;
BIGNUM *start;
BIGNUM *res;
BN_CTX *ctx;
start = BN_new();
ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required
res = start;
BN_hex2bn(&res,"8A9A35145C4EA5260DF9972C804FE2D3F9F3D7A2AC01A6BEB21C82BB30957B3952273AC9166B90C1207347A925780F84A1D2359E7AA05201C674D2B9746FCA07");
eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
group = EC_KEY_get0_group(eckey);
pub_key = EC_POINT_new(group);
printf("private key : "); BN_print_fp(stdout, res); printf("\n");
EC_KEY_set_private_key(eckey, res);
/* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */
if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
printf("Error at EC_POINT_mul.\n");
EC_KEY_set_public_key(eckey, pub_key);
char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);
char *c=cc;
int i;
printf("public key : ");
for (i=0; i<130; i++) // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate
{
printf("%c", *c++);
}
printf("\n");
BN_CTX_free(ctx);
free(cc);
return 0;
}
I own the server and I own the customer's executable. I'd like to establish a secure TLS connection between them.
I can embed whatever I want into the client executable but I'm not sure how to validate a self-assigned certificate that my client received from a connection to the server, i.e. from a SSL_get_peer_certificate call.
I read around that certificates are just public keys with metadata parts signed with the private key. Can I somehow verify that the certificate the server sent me has indeed all the metadata correctly signed by embedding the public key into my client application? Is this possible (and if it is, how?)
I'm not sure how to validate a self-assigned certificate that my client received from a connection to the server ...
Depending on the OpenSSL library you are using, you have to perform two or three steps for verification. The two versions bisect at OpenSSL 1.1.0. OpenSSL 1.1.0 and above performs hostname validation so it only takes two steps. OpenSSL 1.0.2 and below does not perform hostname validation so it requires three steps.
The steps detailed below are from SSL/TLS Client on the OpenSSL wiki.
Server Certificate
Both OpenSSL 1.0.2 and 1.1.0 require you to check for the presence of a certificate. If you use ADH (Anonymous Diffie-Hellman), TLS-PSK (Preshared Key), TLS_SRP (Secure Remote Password), then there may not be a server certificate to verify.
You get the server's certificate with SSL_get_peer_certificate. If it returns non-NULL, then a certificate is present. Lack of a certificate may or may not be a reason to fail.
Certificate Chain
Both OpenSSL 1.0.2 and 1.1.0 require you to check the result of chain validation. Chain validation is part of path building, and its detailed in RFC 4158, Certification Path Building.
You get the result of path validation with SSL_get_verify_result.
Certificate Names
OpenSSL 1.0.2 an below requires you to verify the hostname matches a name listed in the certificate. Its a big topic, but the short of it is: any hostname or dns name needs to be present in the certifcate's Subject Alternative Name (SAN), and not the Common Name (CN). Also see How do you sign Certificate Signing Request with your Certification Authority and How to create a self-signed certificate with openssl? It provides a lot of background information on X.509 server certificates, how to present names, and where the various rules come from.
Effectively, you fetch the SANs with X509_get_ext_d2i(cert, NID_subject_alt_name, ...). Then you loop over the list and extract each name with sk_GENERAL_NAME_num. Then, you extract a GENERAL_NAME entry and ASN1_STRING_to_UTF8, and see if it matches the name you tried to connect to.
Below are the routines for printing the Subject Alternative Name (SAN) and the Common Name (CN). It came from the example on the OpenSSL wiki page.
void print_san_name(const char* label, X509* const cert)
{
int success = 0;
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
{
if(!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
if(!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if(!count) break; /* failed */
for( i = 0; i < count; ++i )
{
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if(!entry) continue;
if(GEN_DNS == entry->type)
{
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if(utf8) {
len2 = (int)strlen((const char*)utf8);
}
if(len1 != len2) {
fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
}
/* If there's a problem with string lengths, then */
/* we skip the candidate and move on to the next. */
/* Another policy would be to fails since it probably */
/* indicates the client is under attack. */
if(utf8 && len1 && len2 && (len1 == len2)) {
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
}
if(utf8) {
OPENSSL_free(utf8), utf8 = NULL;
}
}
else
{
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
}
}
} while (0);
if(names)
GENERAL_NAMES_free(names);
if(utf8)
OPENSSL_free(utf8);
if(!success)
fprintf(stdout, " %s: <not available>\n", label);
}
void print_cn_name(const char* label, X509_NAME* const name)
{
int idx = -1, success = 0;
unsigned char *utf8 = NULL;
do
{
if(!name) break; /* failed */
idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
if(!(idx > -1)) break; /* failed */
X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
if(!entry) break; /* failed */
ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
if(!data) break; /* failed */
int length = ASN1_STRING_to_UTF8(&utf8, data);
if(!utf8 || !(length > 0)) break; /* failed */
fprintf(stdout, " %s: %s\n", label, utf8);
success = 1;
} while (0);
if(utf8)
OPENSSL_free(utf8);
if(!success)
fprintf(stdout, " %s: <not available>\n", label);
}
Verifying my self-signed certificate with openSSL
Because its your self-signed certificate, you can do even better than above. You have a priori knowledge of the host's public key. You can pin the public key, and just use the certificate to deliever the public key or as a presentation detail.
To pin the public key, see Public Key Pinning over at OWASP.
You should also avoid the IETF's RFC 7469, Public Key Pinning Extension for HTTP with Overrides. The IETF's rendition allows the attacker to break a known good pinset so the attacker can MitM the connection. They also suppress reporting the problem, so the user agent becomes complicit in the coverup.
I have an ASN.1 x509 byte array that contains the modulo and the public key of an RSA pair. My goal is to do whatever it takes to use this to encrypt a string. I'm trying to use openssl in objective-c to accomplish this. Whenever I try to get an RSA object using d2i_X509, it returns null. I'm willing to switch to a different library if I can't accomplish this using openssl. Please help me find something that works.
You generally would not encrypt a string using the public key of an X.509 directly. Instead you would generate a strong random(of a specific quality) key; use normal symmetric encryption (such as AES) and then encyrpt the string with that. You then encrypt the random key with the X.509.
Consult a good PKI/Crypto book (e.g. http://www.amazon.com/Applied-Cryptography-Protocols-Algorithms-Source/dp/0471117099) as to why (sections on key leakage, bit-flipping, padding and (re)encrypting twice).
If you really insist on doing this -have a look at https://github.com/dirkx/smime-add-encryption-for-recipient/blob/master/smime-add-encrypt/main.c its pkcs7_encode_rinfo function.
x509cert = ... something to read your x509 byte array in.
unsigned char *stuff = "Some zecret string";
int stufflen = strlen(stuff);
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx = NULL;
assert(pkey = = X509_get_pubkey( x509cert));
assert(pctx = EVP_PKEY_CTX_new(pkey, NULL));
assert(EVP_PKEY_encrypt_init(pctx)==1);
assert((EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT
EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri)==1);
size_t eklen;
assert(EVP_PKEY_encrypt(pctx, NULL, &eklen, stuff, stufflen)==1);
ek = OPENSSL_malloc(eklen);
assert(ek);
unsigned char *ek = NULL;
assert((EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen)==1);
printf("Encrypted blurp: ");
for(int i = 0; i < eklen; i++) {
printf("0x%02X ", ek[i];
};
printf("\n");
exit(0);
I am tring to implement RSA encryption in my app using SecKeyEncrypt and SecKeyDecrypt.
The issue is that only when the ciphertext is long as KeyblockSize (128,256 etc), I get it decrypted correctly. Also, for each build and run, I get different results (encrypted data and cipher text length) keeping input plain text the same. And on clean and build several times, once in a while cipher text length becomes keyblocksize and so decrypts properly.
Pls help to understand where the problem is. Thanks in advance
Note: From SecKeyEncrypt's definition got to know that the last parameter gives back the no. of bytes written, i.e. ciphertextlength in bytes. This parameter always returns back my keyblocksize for any input string.
But many times the actual ciphertext length varies with this parameter. And whenever ciphertextlength is same as the parameter, gets decrypted correctly.
Posting encrypt and decrypt portions of my code :
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer
{
OSStatus status = noErr;
NSLog(#"** original plain text 0: %s", plainBuffer);
size_t plainBufferSize = strlen((char *)plainBuffer);//
size_t cipherBufferSize = CIPHER_BUFFER_SIZE;// its 1024
SecKeyRef key=[self getPublicKeyRef];
NSLog(#"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize(key));//it returns 256
// Error handling
// Encrypt using the public.
status = SecKeyEncrypt([self getPublicKeyRef],
kSecPaddingNone,
plainBuffer,
plainBufferSize,
&cipherBuffer[0],
&cipherBufferSize
);
NSLog(#"encryption result code: %ld (size: %lu)", status, cipherBufferSize);
NSLog(#"encrypted text: %s", cipherBuffer);
}
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer
{
OSStatus status = noErr;
size_t cipherBufferSize = strlen((char *)cipherBuffer);
// DECRYPTION
size_t plainBufferSize = BUFFER_SIZE;//its 256
// Error handling
status = SecKeyDecrypt([self getPrivateKeyRef],
kSecPaddingNone,
&cipherBuffer[0],
cipherBufferSize,
&plainBuffer[0],
&plainBufferSize
);
NSLog(#"decryption result code: %ld (size: %lu)", status, plainBufferSize);
NSLog(#"FINAL decrypted text: %s", plainBuffer);
}
Trying to generate an RSA Public Key given an APIs modulus and exponent. I'm using OpenSSL on iOS 4.2.
Generating the public key manually is an option (see below) however i'm not sure how to include the exponent logic in the modulus
-----BEGIN PUBLIC KEY-----
Modulus from API
-----END PUBLIC KEY-----
Based on #James comments, I am able to write public pem but getting blank private key. Here is my code:
char szModulus = "1162" ;
char *szExp = "827655" ;
RSA* rsa = RSA_new();
int ret = BN_hex2bn(&rsa->n,szModulus) ;
ret = BN_hex2bn(&rsa->d,szExp) ;
FILE *fp = fopen("/Users/ysi/Desktop/privateKey.pem", "wb");
PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, 0, NULL);
To do this make sure you have the OpenSSL library linked (instructions here http://code.google.com/p/ios-static-libraries/)
Once linked you'll have access to several BIGNUM converters. I turned the modulus into hex using the BN_hex2bn method saving the hex string into 'exponent'
Then create the BIGNUM struct and encrypt using RSA_public_encrypt
RSA *rsa = NULL;
rsa->n = BN_new();
BN_copy(rsa->n,modulus);
rsa->e = BN_new();
BN_copy(rsa->e,exponent);
rsa->iqmp=NULL;
rsa->d=NULL;
rsa->p=NULL;
rsa->q=NULL;
Good Luck!