Skip to content

Instantly share code, notes, and snippets.

@davepeck
Last active May 8, 2020 16:05
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save davepeck/93f9ff1beeab0c5616ac8a8589f5fe11 to your computer and use it in GitHub Desktop.
Save davepeck/93f9ff1beeab0c5616ac8a8589f5fe11 to your computer and use it in GitHub Desktop.
Objective-C code to generate a CSR via OpenSSL
//
// CertificateSigningRequest.h
// Cloak
//
// Created by Dave Peck on 10/31/16.
// Copyright © 2016 Bourgeois Bits LLC. All rights reserved.
// Licensed under the MIT license
//
#import <Foundation/Foundation.h>
@interface CertificateSigningRequest: NSObject
+ (nullable NSData *)csrWithPublicKey:(nonnull NSData *)publicKey privateKey:(nonnull NSData *)privateKey;
@end
//
// CertificateSigningRequest.m
// Cloak
//
// Created by Dave Peck on 10/31/16.
// Copyright © 2016 Bourgeois Bits LLC. All rights reserved.
// Licensed under the MIT license
//
#import "CertificateSigningRequest.h"
#import <openssl/x509.h>
@interface CertificateSigningRequest ()
@property (nonatomic, readwrite) NSData *publicKey;
@property (nonatomic, readwrite) NSData *privateKey;
// Intermediate structures.
@property (nonatomic) EVP_PKEY *evpKeyPair;
@property (nonatomic) X509_REQ *request;
@property (nonatomic) BIO *basicOutput;
@end
@implementation CertificateSigningRequest
+ (nullable NSData *)csrWithPublicKey:(nonnull NSData *)publicKey privateKey:(nonnull NSData *)privateKey;
{
return [[[CertificateSigningRequest alloc] initWithPublicKey:publicKey privateKey:privateKey] generate];
}
- (id)initWithPublicKey:(nonnull NSData *)publicKey privateKey:(nonnull NSData *)privateKey
{
self = [super init];
if (self != nil)
{
_publicKey = publicKey;
_privateKey = privateKey;
}
return self;
}
- (void)dealloc
{
if (self.evpKeyPair != NULL) {
EVP_PKEY_free(self.evpKeyPair);
}
if (self.request != NULL) {
X509_REQ_free(self.request);
}
if (self.basicOutput != NULL) {
BIO_free(self.basicOutput);
}
}
- (nullable NSData *)generate
{
NSData *data = nil;
@try
{
[self importKeys];
[self createRequest];
data = [self exportRequest];
}
@catch (NSException *exception)
{
NSLog(@"Error generating CSR: %@", exception.reason);
}
return data;
}
- (void)importKeys
{
EVP_PKEY *evpKeyPair = NULL;
// OpenSSL has terrifying interfaces. Read the implementations of d2i_*Key and cry.
const unsigned char *letOpenSSLOverwriteMe = NULL;
// Wrap the key in an EVP_PKEY.
letOpenSSLOverwriteMe = (const unsigned char *)self.publicKey.bytes;
evpKeyPair = d2i_PublicKey(EVP_PKEY_RSA, NULL, &letOpenSSLOverwriteMe, self.publicKey.length);
if (evpKeyPair == NULL) {
[self failWithReason:@"Failed to add public key data to EVP_PKEY object."];
}
letOpenSSLOverwriteMe = (const unsigned char *)self.privateKey.bytes;
evpKeyPair = d2i_PrivateKey(EVP_PKEY_RSA, &evpKeyPair, &letOpenSSLOverwriteMe, self.privateKey.length);
if (evpKeyPair == NULL) {
[self failWithReason:@"Failed to add private key data to EVP_PKEY object."];
}
self.evpKeyPair = evpKeyPair;
}
- (void)createRequest
{
int success = 0;
self.request = X509_REQ_new();
if (self.request == NULL) {
[self failWithReason:@"Failed to allocate X509_REQ object."];
}
success = X509_REQ_set_pubkey(self.request, self.evpKeyPair);
if (!success) {
[self failWithReason:@"Failed to add keys to the X509_REQ."];
}
success = X509_REQ_sign(self.request, self.evpKeyPair, EVP_sha256());
if (!success) {
[self failWithReason:@"Failed to sign X509_REQ."];
}
}
- (nonnull NSData *)exportRequest
{
BUF_MEM *bufferMemory = NULL;
NSData *data = nil;
int success = 0;
self.basicOutput = BIO_new(BIO_s_mem());
if (self.basicOutput == NULL) {
[self failWithReason:@"Failed to allocate mem BIO."];
}
success = i2d_X509_REQ_bio(self.basicOutput, self.request);
if (!success) {
[self failWithReason:@"Failed to export X509_REQ to BIO."];
}
BIO_get_mem_ptr(self.basicOutput, &bufferMemory);
if (bufferMemory == NULL) {
[self failWithReason:@"Can't get BIO buffer."];
}
data = [NSData dataWithBytes:bufferMemory->data length:bufferMemory->length];
return data;
}
#pragma mark - Utils
- (void)failWithReason:(nonnull NSString *)reason
{
@throw [NSException exceptionWithName:NSGenericException reason:reason userInfo:nil];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment