HTTP Public Key Pinning (HPKP) without Openssl - ssl

I am planning to generate following pin-sha256 :
Public-Key-Pins:
pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=";
pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=";
max-age=5184000; includeSubDomains;
report-uri="https://www.example.org/hpkp-report"
So that i can keep in IIS for security reasons as below:
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="Public-Key-Pins" value="pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubDomains" />
</customHeaders>
</httpProtocol>
...
</system.webServ
But my server lacks open ssl and take long time to install because of process issues.
Could you please let me know is there any alternative without these openssl that i can generate pins?
See this link for more details
These are the pin generation commands, i need to do this without openssl , is it possible?
openssl rsa -in my-rsa-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

Here is an example of the openssl command chain above converted into openssl API calls that output the base64 result to the screen.
The main calls are
PEM_read_bio_PrivateKey to read in the private key in PEM format.
i2d_RSA_PUBKEY_bio to convert the RSA public key into DER format
EVP_Digest to create the SHA256 digest (hidden behind the BIO_f_md BIO usage)
BIO_f_base64 BIO usage to convert the digest into base64 format
There are lots of ways to do the same job using variations of the above OPENSSL API's depending on your situation.
Below is a C++ usage of the OpenSSL C API. You can easily strip the C++ bits if required.
template<typename T, typename D>
std::unique_ptr<T, D> make_handle(T* handle, D deleter)
{
return std::unique_ptr<T, D>{handle, deleter};
}
bool load_rsa_private_key_and_base64_sha256_hash_public_key()
{
// load rsa private key in PEM format
auto bio = make_handle(BIO_new_file("privatekey.pem", "rb"), BIO_free);
if(!bio) return false;
auto const key = make_handle(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, (void*)("password")), EVP_PKEY_free);
bio.reset();
if(!key) return false;
// extract private key from loaded certificate
auto const rsa = EVP_PKEY_get0_RSA(key.get());
if (!rsa) return false;
// setup sha256 bio chain
auto const bmd = make_handle(BIO_new(BIO_f_md()), BIO_free);
if(!bmd) return false;
if (!BIO_set_md(bmd.get(), EVP_sha256())) return false;
auto const null_bio = make_handle(BIO_new(BIO_s_null()), BIO_free);
auto in = BIO_push(bmd.get(), null_bio.get());
// write RSA Public Key into DER format to the SHA256 digest BIO chain
i2d_RSA_PUBKEY_bio(in, rsa);
// extract the SHA256 digest
auto mdtmp = BIO_find_type(in, BIO_TYPE_MD);
if (!mdtmp) return false;
std::array<char, EVP_MAX_MD_SIZE> buffer;
auto const length = BIO_gets(mdtmp, buffer.data(), buffer.size());
if(length <= 0) return false;
// convert the digest to base64 and output to the stdio
auto const b64 = make_handle(BIO_new(BIO_f_base64()), BIO_free);
auto const bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
auto out = BIO_push(b64.get(), bio_out);
BIO_write(out, buffer.data(), length);
BIO_flush(out);
return true;
}

Related

Generate private/public pair key using ECC : elliptic curves

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

OpenSSL X509 certificate to string

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

Extract public key from private key in pem format

How can I implement the effect of following command in Objective-C?
openssl rsa -in mykey.pem -pubout > mykey.pub
I'm able to generate a private key in pem format.
Here is the code I use to read the private key into a openssl RSA object.
BIO* bpPrivate = nil;
NSString *filePath = .....
const char *path = [filePath UTF8String];
bpPrivate = BIO_new_file(path, "r");
_rsa = PEM_read_bio_RSAPrivateKey(bpPrivate, NULL, 0, NULL);
I want to extract the public key from the private key.
In memory, there is no notion of ASN.1, DER, PEM or other encodings. A RSA key uses the same structure for both the public and private key. For a public key, some fields are not used. If you are interested in the fields, then visit PKCS #1 or RFC 3447.
So, given an RSA*, all you need to do is call PEM_write_bio_RSAPublicKey (even with a private key). You can also use PEM_write_RSAPublicKey (even with a private key). See pem(3) for all the read and write functions.
You can also accomplish it the long way by way of RSAPublicKey_dup. It will take a priavte key (i.e., a RSA*) and return a public key (i.e., a RSA*). But its kind of an unnecessary step for the most part. It might be useful to keep the key in memory, if you have that requirement.
RSA* privKey = NULL;
RSA* pubKey = NULL;
BIGNUM* exp = NULL;
privKey = RSA_new();
ASSERT(privKey != NULL);
exp = BN_new();
ASSERT(exp != NULL);
rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);
rc = RSA_generate_key_ex(privKey, 1024, exp, NULL);
ASSERT(rc == 1);
pubKey = RSAPublicKey_dup(privKey);
ASSERT(pubKey != NULL);
RSA_print_fp(stdout, pubKey, 0);
if(pubKey) {
RSA_free(pubKey);
}
if(privKey) {
RSA_free(privKey);
}
if(exp) {
BN_free(exp);
}
The RSA_print_fp results in:
$ ./t.exe
Public-Key: (1024 bit)
Modulus:
00:c3:30:67:d9:11:59:9b:85:7a:1a:95:fa:fd:c0:
dd:cd:21:d6:41:6b:16:70:c2:57:9a:f2:d2:bd:3b:
c0:02:7b:6a:ab:7f:13:a7:53:2f:31:10:08:3a:62:
28:40:5f:82:19:23:f6:0f:78:f5:e3:e4:19:a1:b4:
73:65:35:10:db:17:28:41:42:ba:df:8c:18:3b:d8:
62:52:65:61:0e:cd:60:28:c9:75:a8:5b:46:a4:89:
db:78:89:49:87:5d:7f:ce:d0:44:c4:fd:4a:74:66:
d4:46:21:c1:89:97:28:de:43:e9:94:50:f1:36:85:
a7:ef:6c:6d:6f:5d:78:00:67
Exponent: 65537 (0x10001)
You can add a call to PEM_write_RSAPublicKey:
FILE* file = fopen("rsa-pub.pem", "w");
ASSERT(file != NULL);
rc = PEM_write_RSAPublicKey(file, pubKey);
Then:
$ ./t.exe
$ cat rsa-pub.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMb2jIVcTttHRqG9szv3CFZ742l7LxnVoM6oOfQXNOwabh+GB4Srf4IA
XRcGan7cj1DShnoPw9fp3IeuAUerk3xz8yPXCw09dLwrFcsmItLVnSLoRtpHnxN5
30Wd5vKpvKTLIQnurGo05s911ukFJeGo2y2OjSnTiQcJLUdt497tAgMBAAE=
-----END RSA PUBLIC KEY-----

How do I encrypt a string with an RSA public key from a ASN.1 x509 Byte array?

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

Initialize Public Key From Modulus & Exponent using OpenSSL

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!