blob: a658d9cb0e2c22bb8ebdfad2442692ebfdbfbc73 [file] [log] [blame]
Ed Tanous0fdddb12017-02-28 11:06:34 -08001#pragma once
2
3#include <openssl/bio.h>
4#include <openssl/dh.h>
5#include <openssl/dsa.h>
6#include <openssl/dsa.h>
7#include <openssl/err.h>
8#include <openssl/evp.h>
9#include <openssl/pem.h>
10#include <openssl/rand.h>
11#include <openssl/rsa.h>
12#include <openssl/ssl.h>
13
14namespace ensuressl
15{
16static void init_openssl(void);
17static void cleanup_openssl(void);
18static EVP_PKEY *create_rsa_key(void);
19static void handle_openssl_error(void);
20
21inline bool verify_openssl_key_cert(const std::string &filepath)
22{
23 bool private_key_valid = false;
24 bool cert_valid = false;
25 FILE *file = fopen(filepath.c_str(), "r");
26 if (file != NULL){
27 EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
28 int rc;
29 if (pkey) {
30 int type = EVP_PKEY_type(pkey->type);
31 switch (type) {
32 case EVP_PKEY_RSA:
33 case EVP_PKEY_RSA2: {
34 RSA *rsa = EVP_PKEY_get1_RSA(pkey);
35 rc = RSA_check_key(rsa);
36 if (rc == 1) {
37 private_key_valid = true;
38 }
39
40 //RSA_free(rsa);
41
42 break;
43 }
44 default:
45 break;
46 }
47
48 if (private_key_valid) {
49 X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
50 unsigned long err = ERR_get_error();
51
52 rc = X509_verify(x509, pkey);
53 err = ERR_get_error();
54 if (err == 0 && rc == 1) {
55 cert_valid = true;
56 }
57 }
58
59 EVP_PKEY_free(pkey);
60 }
61 fclose(file);
62 }
63 return cert_valid;
64}
65
66inline void generate_ssl_certificate(const std::string &filepath)
67{
68 EVP_PKEY *pPrivKey = NULL;
69 FILE *pFile = NULL;
70 init_openssl();
71
72 pPrivKey = create_rsa_key();
73
74 // Use this code to directly generate a certificate
75 X509 *x509;
76 x509 = X509_new();
77 if (x509) {
78 // TODO get actually random int
79 ASN1_INTEGER_set(X509_get_serialNumber(x509), 1584);
80
81 // not before this moment
82 X509_gmtime_adj(X509_get_notBefore(x509), 0);
83 // Cert is valid for 10 years
84 X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L);
85
86 // set the public key to the key we just generated
87 X509_set_pubkey(x509, pPrivKey);
88
89 // Get the subject name
90 X509_NAME *name;
91 name = X509_get_subject_name(x509);
92
93 X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1,
94 -1, 0);
95 X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
96 (unsigned char *)"Intel BMC", -1, -1, 0);
97 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
98 (unsigned char *)"testhost", -1, -1, 0);
99 // set the CSR options
100 X509_set_issuer_name(x509, name);
101
102 // Sign the certificate with our private key
103 X509_sign(x509, pPrivKey, EVP_sha256());
104
105 pFile = fopen(filepath.c_str(), "wt");
106
107 if (pFile) {
108 PEM_write_PrivateKey(pFile, pPrivKey, NULL, NULL, 0, 0, NULL);
109 PEM_write_X509(pFile, x509);
110 fclose(pFile);
111 pFile = NULL;
112 }
113
114 X509_free(x509);
115 }
116
117 if (pPrivKey) {
118 EVP_PKEY_free(pPrivKey);
119 pPrivKey = NULL;
120 }
121
122 //cleanup_openssl();
123}
124
125EVP_PKEY *create_rsa_key(void)
126{
127 RSA *pRSA = NULL;
128 EVP_PKEY *pKey = NULL;
129 pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
130 pKey = EVP_PKEY_new();
131 if (pRSA && pKey && EVP_PKEY_assign_RSA(pKey, pRSA)) {
132 /* pKey owns pRSA from now */
133 if (RSA_check_key(pRSA) <= 0) {
134 fprintf(stderr, "RSA_check_key failed.\n");
135 handle_openssl_error();
136 EVP_PKEY_free(pKey);
137 pKey = NULL;
138 }
139 } else {
140 handle_openssl_error();
141 if (pRSA) {
142 RSA_free(pRSA);
143 pRSA = NULL;
144 }
145 if (pKey) {
146 EVP_PKEY_free(pKey);
147 pKey = NULL;
148 }
149 }
150 return pKey;
151}
152
153void init_openssl(void)
154{
155 if (SSL_library_init()) {
156 SSL_load_error_strings();
157 OpenSSL_add_all_algorithms();
158 RAND_load_file("/dev/urandom", 1024);
159 } else
160 exit(EXIT_FAILURE);
161}
162
163void cleanup_openssl(void)
164{
165 CRYPTO_cleanup_all_ex_data();
166 ERR_free_strings();
167 ERR_remove_thread_state(0);
168 EVP_cleanup();
169}
170
171void handle_openssl_error(void) { ERR_print_errors_fp(stderr); }
172inline void ensure_openssl_key_present_and_valid(const std::string &filepath)
173{
174 bool pem_file_valid = false;
175
176 pem_file_valid = verify_openssl_key_cert(filepath);
177
178 if (!pem_file_valid) {
179 generate_ssl_certificate(filepath);
180 }
181}
182}