]>
Commit | Line | Data |
---|---|---|
0f113f3e MC |
1 | /* |
2 | * Certificate creation. Demonstrates some certificate related operations. | |
96bd6f73 DSH |
3 | */ |
4 | ||
96bd6f73 DSH |
5 | #include <stdio.h> |
6 | #include <stdlib.h> | |
7 | ||
8 | #include <openssl/pem.h> | |
9 | #include <openssl/conf.h> | |
10 | #include <openssl/x509v3.h> | |
0b13e9f0 | 11 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 12 | # include <openssl/engine.h> |
0b13e9f0 | 13 | #endif |
96bd6f73 DSH |
14 | |
15 | int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); | |
16 | int add_ext(X509 *cert, int nid, char *value); | |
17 | ||
18 | int main(int argc, char **argv) | |
0f113f3e MC |
19 | { |
20 | BIO *bio_err; | |
21 | X509 *x509 = NULL; | |
22 | EVP_PKEY *pkey = NULL; | |
96bd6f73 | 23 | |
0f113f3e | 24 | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); |
96bd6f73 | 25 | |
0f113f3e | 26 | bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); |
96bd6f73 | 27 | |
0f113f3e | 28 | mkcert(&x509, &pkey, 512, 0, 365); |
96bd6f73 | 29 | |
0f113f3e MC |
30 | RSA_print_fp(stdout, pkey->pkey.rsa, 0); |
31 | X509_print_fp(stdout, x509); | |
96bd6f73 | 32 | |
0f113f3e MC |
33 | PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL); |
34 | PEM_write_X509(stdout, x509); | |
96bd6f73 | 35 | |
0f113f3e MC |
36 | X509_free(x509); |
37 | EVP_PKEY_free(pkey); | |
96bd6f73 | 38 | |
0b13e9f0 | 39 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 40 | ENGINE_cleanup(); |
0b13e9f0 | 41 | #endif |
0f113f3e | 42 | CRYPTO_cleanup_all_ex_data(); |
96bd6f73 | 43 | |
0f113f3e MC |
44 | CRYPTO_mem_leaks(bio_err); |
45 | BIO_free(bio_err); | |
46 | return (0); | |
47 | } | |
96bd6f73 DSH |
48 | |
49 | static void callback(int p, int n, void *arg) | |
0f113f3e MC |
50 | { |
51 | char c = 'B'; | |
52 | ||
53 | if (p == 0) | |
54 | c = '.'; | |
55 | if (p == 1) | |
56 | c = '+'; | |
57 | if (p == 2) | |
58 | c = '*'; | |
59 | if (p == 3) | |
60 | c = '\n'; | |
61 | fputc(c, stderr); | |
62 | } | |
96bd6f73 DSH |
63 | |
64 | int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days) | |
0f113f3e MC |
65 | { |
66 | X509 *x; | |
67 | EVP_PKEY *pk; | |
68 | RSA *rsa; | |
69 | X509_NAME *name = NULL; | |
70 | ||
71 | if ((pkeyp == NULL) || (*pkeyp == NULL)) { | |
72 | if ((pk = EVP_PKEY_new()) == NULL) { | |
73 | abort(); | |
74 | return (0); | |
75 | } | |
76 | } else | |
77 | pk = *pkeyp; | |
78 | ||
79 | if ((x509p == NULL) || (*x509p == NULL)) { | |
80 | if ((x = X509_new()) == NULL) | |
81 | goto err; | |
82 | } else | |
83 | x = *x509p; | |
84 | ||
85 | rsa = RSA_generate_key(bits, RSA_F4, callback, NULL); | |
86 | if (!EVP_PKEY_assign_RSA(pk, rsa)) { | |
87 | abort(); | |
88 | goto err; | |
89 | } | |
90 | rsa = NULL; | |
91 | ||
92 | X509_set_version(x, 2); | |
93 | ASN1_INTEGER_set(X509_get_serialNumber(x), serial); | |
94 | X509_gmtime_adj(X509_get_notBefore(x), 0); | |
95 | X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days); | |
96 | X509_set_pubkey(x, pk); | |
97 | ||
98 | name = X509_get_subject_name(x); | |
99 | ||
100 | /* | |
101 | * This function creates and adds the entry, working out the correct | |
102 | * string type and performing checks on its length. Normally we'd check | |
103 | * the return value for errors... | |
104 | */ | |
105 | X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, "UK", -1, -1, 0); | |
106 | X509_NAME_add_entry_by_txt(name, "CN", | |
107 | MBSTRING_ASC, "OpenSSL Group", -1, -1, 0); | |
108 | ||
109 | /* | |
110 | * Its self signed so set the issuer name to be the same as the subject. | |
111 | */ | |
112 | X509_set_issuer_name(x, name); | |
113 | ||
114 | /* Add various extensions: standard extensions */ | |
115 | add_ext(x, NID_basic_constraints, "critical,CA:TRUE"); | |
116 | add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign"); | |
117 | ||
118 | add_ext(x, NID_subject_key_identifier, "hash"); | |
119 | ||
120 | /* Some Netscape specific extensions */ | |
121 | add_ext(x, NID_netscape_cert_type, "sslCA"); | |
122 | ||
123 | add_ext(x, NID_netscape_comment, "example comment extension"); | |
96bd6f73 DSH |
124 | |
125 | #ifdef CUSTOM_EXT | |
0f113f3e MC |
126 | /* Maybe even add our own extension based on existing */ |
127 | { | |
128 | int nid; | |
129 | nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension"); | |
130 | X509V3_EXT_add_alias(nid, NID_netscape_comment); | |
131 | add_ext(x, nid, "example comment alias"); | |
132 | } | |
96bd6f73 | 133 | #endif |
0f113f3e MC |
134 | |
135 | if (!X509_sign(x, pk, EVP_sha1())) | |
136 | goto err; | |
137 | ||
138 | *x509p = x; | |
139 | *pkeyp = pk; | |
140 | return (1); | |
141 | err: | |
142 | return (0); | |
143 | } | |
144 | ||
145 | /* | |
146 | * Add extension using V3 code: we can set the config file as NULL because we | |
147 | * wont reference any other sections. | |
96bd6f73 DSH |
148 | */ |
149 | ||
150 | int add_ext(X509 *cert, int nid, char *value) | |
0f113f3e MC |
151 | { |
152 | X509_EXTENSION *ex; | |
153 | X509V3_CTX ctx; | |
154 | /* This sets the 'context' of the extensions. */ | |
155 | /* No configuration database */ | |
156 | X509V3_set_ctx_nodb(&ctx); | |
157 | /* | |
158 | * Issuer and subject certs: both the target since it is self signed, no | |
159 | * request and no CRL | |
160 | */ | |
161 | X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); | |
162 | ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); | |
163 | if (!ex) | |
164 | return 0; | |
165 | ||
166 | X509_add_ext(cert, ex, -1); | |
167 | X509_EXTENSION_free(ex); | |
168 | return 1; | |
169 | } |