├── readme.txt ├── ca.pem ├── root.key └── main.cpp /readme.txt: -------------------------------------------------------------------------------- 1 | source code for my post on stackoverflow.com 2 | 3 | https://stackoverflow.com/questions/38949576/how-to-programmatically-create-a-certificate-signing-request-csr 4 | -------------------------------------------------------------------------------- /ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDuzCCAqOgAwIBAgIUXLtswJ6xGq5sGyRjBhnBZ8gkyuYwDQYJKoZIhvcNAQEL 3 | BQAwbTELMAkGA1UEBhMCUlUxDTALBgNVBAgMBE1JVE0xDTALBgNVBAcMBE1JVE0x 4 | DTALBgNVBAoMBE1JVE0xDTALBgNVBAsMBE1JVE0xDTALBgNVBAMMBE1JVE0xEzAR 5 | BgkqhkiG9w0BCQEWBE1JVE0wHhcNMTkwODIwMTYzMTM4WhcNMjAwODE5MTYzMTM4 6 | WjBtMQswCQYDVQQGEwJSVTENMAsGA1UECAwETUlUTTENMAsGA1UEBwwETUlUTTEN 7 | MAsGA1UECgwETUlUTTENMAsGA1UECwwETUlUTTENMAsGA1UEAwwETUlUTTETMBEG 8 | CSqGSIb3DQEJARYETUlUTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 9 | ANsVTMll+Hd7PetePL23k1/PBenqwqbo/CPaLqlEksMbq4CTuGPydN642DUL19q7 10 | fdW+rgvurf4Ex6i48kVnVPoPfqN/aOI/RUwllF8UWs/yglSdfcXckG9jmcy4pNet 11 | nIP/r1RjDU24LSAcPxH5vowW5w0382HC3lGnLPKE2TItHy2SeBqSjd30SosX0MhD 12 | pzrTyGr83MwPITZEQsWJJ60g3q+rPvl9rDPQwbFJMiaZ8B24ZysS3Pqij49BIw0z 13 | sDTkZMvsVOJDhSSNRssu/E8i/GNXdY6XwY4CT2JlNfaJRabHDChYv3SfXwjPaQwq 14 | VL7XOPesIBiWIr4vHYPjl7UCAwEAAaNTMFEwHQYDVR0OBBYEFK8+m6ZDqVBklHKu 15 | BWSDARueau4xMB8GA1UdIwQYMBaAFK8+m6ZDqVBklHKuBWSDARueau4xMA8GA1Ud 16 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAF1kF6OPMTYbaqL4kW4gd32t 17 | o/ypt0e5jx00HaAGvKsgrW28I7CTvbnhkDMNr5O5GBwWzwjj2IURl3xUWI2qxn/0 18 | 2bDFcZzc3Hbj7nDZO4GOjL7G7vah/2p0nWOK0FaTDrvYe91H8q7OMRnQbUwOUqNb 19 | X9zJelQ/3q86dO5cb3wJzwHA6LpgoOMnuhufXY7ugMj944dG2olKKGKw1qUHIl2g 20 | U9I46Tghlj3GPPq35zmB1oPt0kk5VM/ItlC1tk4zfTsvyQE14L7q+QV9BMvo4zQH 21 | j7XG8+/pbU6EwgByLHnzAqu/YwQmcyDtdUM+h9Dl+il3K+mdnAMm0K3377rO7zI= 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /root.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDbFUzJZfh3ez3r 3 | Xjy9t5NfzwXp6sKm6Pwj2i6pRJLDG6uAk7hj8nTeuNg1C9fau33Vvq4L7q3+BMeo 4 | uPJFZ1T6D36jf2jiP0VMJZRfFFrP8oJUnX3F3JBvY5nMuKTXrZyD/69UYw1NuC0g 5 | HD8R+b6MFucNN/Nhwt5RpyzyhNkyLR8tkngako3d9EqLF9DIQ6c608hq/NzMDyE2 6 | RELFiSetIN6vqz75fawz0MGxSTImmfAduGcrEtz6oo+PQSMNM7A05GTL7FTiQ4Uk 7 | jUbLLvxPIvxjV3WOl8GOAk9iZTX2iUWmxwwoWL90n18Iz2kMKlS+1zj3rCAYliK+ 8 | Lx2D45e1AgMBAAECggEBAIbAhShjNf6XqTA6GHZAkb8eYO7N3Mg5Cc0riAPJD9Q+ 9 | ErDVK1cebFAJtcJ69Fuvcuijjf384rwZSI04pJuXwSbFnQkHdwWiEQeTHb2VkX3S 10 | FePhstien6BDzPekoo+eU2TFQZxQCIDDRc44UXrG+DLGa3sv7N02tPPYNcc9ezJm 11 | ds6fYiQzL108CMFE3H8bKpgKuAwFpzb26BCxLIMEXlpN8QAslCZSMWkcyVFdIhow 12 | n63TO9GSYUrjqVtcEyccGHdPLaUvE9pzXCDOyPNPiAXVbbEG2+/xVlmdG/yzYl/p 13 | APbv7YqXVy1NkhhK/KG3PJaYDbModYOgHnKl6cLTg4kCgYEA+T0R8CKiphe6RkYS 14 | 7RZw63SaiViGI4EKD1gVNKQn+seQ6AS/x+guV3+QymdMDxDhBQ+9hxut+RD1c8hD 15 | iVWukUMzevuiQDebVbDufWMC9lAbbktw/linMCz9LH7kNwVH8GkMV+dhCBaMDtID 16 | D5L2lOB237koXfxb2aNu8ffPSTMCgYEA4QbOB/198yB5nQxl4UtS3mdfafxqbvwn 17 | sA5DmUMYvgvBC/rqufLF7VSbGNH4CM9DHK1AdOeWDXOYrs3aY3LCLhNQeh0hFhEZ 18 | no0YAxJH65f8Ny+2UhQ1f1YzpuWxSwd8pMqYv/LY8R4OCIb9MZ/KUxfyzvegUd2z 19 | QTmC9WvPK3cCgYB/WBmrNTcfX+4366PN6XJmi1xOIqHe0BagwmOLUvhuZLsAITUP 20 | 4eyTnkUPdXniFMC0AlfXCWh5YpXWw5LmP5YC+G/8PUeoQgEm5lDkVct0qHdrgjZI 21 | bml17vaoXmkiR5t7FWFOJJVqOYL0K4+OzIsahBmYs5UReFhBugR8sx4BCwKBgQCC 22 | xXeagSBe2HKUaA4U/bcs9Jood75KvVM7Jy71tF5+o0oO8kTSx1lq8Q4pQGyKghiY 23 | Y77fsW4sZw9GFu9hd+GM8UCFlsQRlOJ0l75qmocdTPgQAjRMQt5MIAZoaXe9CJ7R 24 | DcPzWOfmR/cT0Y729cuYuoQq7xFGQjbYItoOUhbVRQKBgGC80WrJJp3Z+GYq0HB7 25 | C/9Gf9w437GXpX7KXrue+ftJRQKJtlkiUdlsbf2Gxgvt+GZi4YqmKbzpd18cIUxD 26 | o97pDeSqL2ZbEbK9o4ZMcjHxHXcdzr00BO5nK62+yPoxLXFjoSQokqk+xEgsyWEF 27 | 13WtSNAuCrFoDldgQoSwI5+t 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | // include on Windows 7 | 8 | #ifdef _WIN32 9 | #include 10 | #endif 11 | 12 | #define CERT_REQUEST_KEY_PATH "root.key" 13 | #define GENERATED_CERT_REQUEST_SAVE_PATH "generated_request.csr" 14 | 15 | #define CERT_CA_PATH "ca.pem" 16 | #define CERT_CA_KEY_PATH "root.key" 17 | #define GENERATED_CERT_SAVE_PATH "generated_cert.crt" 18 | 19 | // the app mimics the following two commands. 20 | // 21 | // openssl req -new -key CERT_REQUEST_KEY_PATH -out GENERATED_CERT_REQUEST_SAVE_PATH 22 | // openssl x509 -req -in GENERATED_CERT_SAVE_PATH -CA CERT_CA_PATH -CAkey CERT_CA_KEY_PATH -CAcreateserial -out GENERATED_CERT_SAVE_PATH -days 5000 23 | 24 | X509_REQ *generate_cert_req(const char *p_path) { 25 | FILE *p_file = NULL; 26 | EVP_PKEY *p_key = NULL; 27 | X509_REQ *p_x509_req = NULL; 28 | 29 | if (NULL == (p_file = fopen(p_path, "r"))) { 30 | printf("failed to open the private key file\n"); 31 | goto CLEANUP; 32 | } 33 | 34 | if (NULL == (p_key = PEM_read_PrivateKey(p_file, NULL, NULL, NULL))) { 35 | printf("failed to read the private key file\n"); 36 | goto CLEANUP; 37 | } 38 | 39 | if (NULL == (p_x509_req = X509_REQ_new())) { 40 | printf("failed to create a new X509 REQ\n"); 41 | goto CLEANUP; 42 | } 43 | 44 | if (0 > X509_REQ_set_pubkey(p_x509_req, p_key)) { 45 | printf("failed to set pub key\n"); 46 | X509_REQ_free(p_x509_req); 47 | p_x509_req = NULL; 48 | goto CLEANUP; 49 | } 50 | 51 | if (0 > X509_REQ_sign(p_x509_req, p_key, EVP_sha256())) { 52 | printf("failed to sign the certificate\n"); 53 | X509_REQ_free(p_x509_req); 54 | p_x509_req = NULL; 55 | goto CLEANUP; 56 | } 57 | 58 | CLEANUP: 59 | fclose(p_file); 60 | EVP_PKEY_free(p_key); 61 | 62 | return p_x509_req; 63 | } 64 | 65 | int randSerial(ASN1_INTEGER *ai) { 66 | BIGNUM *p_bignum = NULL; 67 | int ret = -1; 68 | 69 | if (NULL == (p_bignum = BN_new())) { 70 | goto CLEANUP; 71 | } 72 | 73 | if (!BN_pseudo_rand(p_bignum, 64, 0, 0)) { 74 | goto CLEANUP; 75 | } 76 | 77 | if (ai && !BN_to_ASN1_INTEGER(p_bignum, ai)) { 78 | goto CLEANUP; 79 | } 80 | 81 | ret = 1; 82 | 83 | CLEANUP: 84 | BN_free(p_bignum); 85 | 86 | return ret; 87 | } 88 | 89 | X509 *generate_cert(X509_REQ *pCertReq, const char *p_ca_path, const char *p_ca_key_path) { 90 | FILE *p_ca_file = NULL; 91 | X509 *p_ca_cert = NULL; 92 | EVP_PKEY *p_ca_pkey = NULL; 93 | FILE *p_ca_key_file = NULL; 94 | EVP_PKEY *p_ca_key_pkey = NULL; 95 | X509 *p_generated_cert = NULL; 96 | ASN1_INTEGER *p_serial_number = NULL; 97 | EVP_PKEY *p_cert_req_pkey = NULL; 98 | 99 | if (NULL == (p_ca_file = fopen(p_ca_path, "r"))) { 100 | printf("failed to open the ca file\n"); 101 | goto CLEANUP; 102 | } 103 | 104 | if (NULL == (p_ca_cert = PEM_read_X509(p_ca_file, NULL, 0, NULL))) { 105 | printf("failed to read X509 CA certificate\n"); 106 | goto CLEANUP; 107 | } 108 | 109 | if (NULL == (p_ca_pkey = X509_get_pubkey(p_ca_cert))) { 110 | printf("failed to get X509 CA pkey\n"); 111 | goto CLEANUP; 112 | } 113 | 114 | if (NULL == (p_ca_key_file = fopen(p_ca_key_path, "r"))) { 115 | printf("failed to open the private key file\n"); 116 | goto CLEANUP; 117 | } 118 | 119 | if (NULL == (p_ca_key_pkey = PEM_read_PrivateKey(p_ca_key_file, NULL, NULL, NULL))) { 120 | printf("failed to read the private key file\n"); 121 | goto CLEANUP; 122 | } 123 | 124 | if (NULL == (p_generated_cert = X509_new())) { 125 | printf("failed to allocate a new X509\n"); 126 | goto CLEANUP; 127 | } 128 | 129 | p_serial_number = ASN1_INTEGER_new(); 130 | randSerial(p_serial_number); 131 | X509_set_serialNumber(p_generated_cert, p_serial_number); 132 | 133 | X509_set_issuer_name(p_generated_cert, X509_REQ_get_subject_name(pCertReq)); 134 | X509_set_subject_name(p_generated_cert, X509_REQ_get_subject_name(pCertReq)); 135 | 136 | X509_gmtime_adj(X509_get_notBefore(p_generated_cert), 0L); 137 | X509_gmtime_adj(X509_get_notAfter(p_generated_cert), 31536000L); 138 | 139 | if (NULL == (p_cert_req_pkey = X509_REQ_get_pubkey(pCertReq))) { 140 | printf("failed to get certificate req pkey\n"); 141 | X509_free(p_generated_cert); 142 | p_generated_cert = NULL; 143 | goto CLEANUP; 144 | } 145 | 146 | if (0 > X509_set_pubkey(p_generated_cert, p_cert_req_pkey)) { 147 | printf("failed to set pkey\n"); 148 | X509_free(p_generated_cert); 149 | p_generated_cert = NULL; 150 | goto CLEANUP; 151 | } 152 | 153 | if (0 > EVP_PKEY_copy_parameters(p_ca_pkey, p_ca_key_pkey)) { 154 | printf("failed to copy parameters\n"); 155 | X509_free(p_generated_cert); 156 | p_generated_cert = NULL; 157 | goto CLEANUP; 158 | } 159 | 160 | X509_set_issuer_name(p_generated_cert, X509_get_subject_name(p_ca_cert)); 161 | 162 | if (0 > X509_sign(p_generated_cert, p_ca_key_pkey, EVP_sha256())) { 163 | printf("failed to sign the certificate\n"); 164 | X509_free(p_generated_cert); 165 | p_generated_cert = NULL; 166 | goto CLEANUP; 167 | } 168 | 169 | CLEANUP: 170 | fclose(p_ca_file); 171 | X509_free(p_ca_cert); 172 | EVP_PKEY_free(p_ca_pkey); 173 | fclose(p_ca_key_file); 174 | EVP_PKEY_free(p_ca_key_pkey); 175 | ASN1_INTEGER_free(p_serial_number); 176 | EVP_PKEY_free(p_cert_req_pkey); 177 | 178 | return p_generated_cert; 179 | } 180 | 181 | int save_cert_req(X509_REQ *p_cert_req, const char *path) { 182 | FILE *p_file = NULL; 183 | if (NULL == (p_file = fopen(path, "w"))) { 184 | printf("failed to open file for saving csr\n"); 185 | return -1; 186 | } 187 | 188 | PEM_write_X509_REQ(p_file, p_cert_req); 189 | fclose(p_file); 190 | return 0; 191 | } 192 | 193 | int save_cert(X509 *p_generated_cert, const char *path) { 194 | FILE *p_file = NULL; 195 | if (NULL == (p_file = fopen(path, "w"))) { 196 | printf("failed to open file for saving csr\n"); 197 | return -1; 198 | } 199 | 200 | PEM_write_X509(p_file, p_generated_cert); 201 | fclose(p_file); 202 | return 0; 203 | } 204 | 205 | int main() { 206 | int ret = 0; 207 | X509_REQ *p_cert_req = NULL; 208 | X509 *p_generated_cert = NULL; 209 | 210 | p_cert_req = generate_cert_req(CERT_REQUEST_KEY_PATH); 211 | if (NULL == p_cert_req) { 212 | printf("failed to generate cert req\n"); 213 | ret = -1; 214 | goto CLEANUP; 215 | } 216 | 217 | if (save_cert_req(p_cert_req, GENERATED_CERT_REQUEST_SAVE_PATH)) { 218 | printf("failed to save generated cert request\n"); 219 | ret = -1; 220 | goto CLEANUP; 221 | } 222 | 223 | p_generated_cert = generate_cert(p_cert_req, CERT_CA_PATH, CERT_CA_KEY_PATH); 224 | if (NULL == p_generated_cert) { 225 | printf("failed to generate cert\n"); 226 | ret = -1; 227 | goto CLEANUP; 228 | } 229 | 230 | if (save_cert(p_generated_cert, GENERATED_CERT_SAVE_PATH)) { 231 | printf("failed to save generated cert\n"); 232 | ret = -1; 233 | goto CLEANUP; 234 | } 235 | 236 | printf("the certificates have been generated."); 237 | 238 | CLEANUP: 239 | X509_REQ_free(p_cert_req); 240 | X509_free(p_generated_cert); 241 | 242 | return ret; 243 | } 244 | --------------------------------------------------------------------------------