xref: /openbmc/bmcweb/include/ssl_key_handler.hpp (revision 5f34a9c5820b4a60352f40cb7fa86011012b9801)
1 #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 
14 namespace ensuressl
15 {
16 static void init_openssl(void);
17 static void cleanup_openssl(void);
18 static EVP_PKEY *create_rsa_key(void);
19 static void handle_openssl_error(void);
20 
21 inline 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 
66 inline 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 
125 EVP_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 
153 void 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 
163 void 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 
171 void handle_openssl_error(void) { ERR_print_errors_fp(stderr); }
172 inline 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 }