Branch data Line data Source code
1 : : /* smime-qry.c - Get string representations of various certificate parameters
2 : : *
3 : : * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
4 : : * License: This software may be distributed under the same license
5 : : * terms as openssl (i.e. free, but mandatory attribution).
6 : : *
7 : : * 27.9.1999, Created. --Sampo
8 : : * 30.9.1999, added PKCS12 stuff, --Sampo
9 : : * 1.10.1999, improved error reporting, --Sampo
10 : : * 6.10.1999, forked from keygen.c --Sampo
11 : : * 9.10.1999, reviewed for double frees --Sampo
12 : : * 18.10.1999, fixed 256 limit in calls to X509_NAME_oneline() --Sampo
13 : : */
14 : :
15 : : #include "platform.h"
16 : :
17 : : #include <stdio.h>
18 : : #include <string.h>
19 : : #include <time.h>
20 : :
21 : : #ifdef __MWERKS__
22 : : # include "macglue.h"
23 : : #endif
24 : :
25 : : #include <openssl/crypto.h>
26 : : #include <openssl/buffer.h>
27 : : #include <openssl/err.h>
28 : : #include <openssl/rand.h>
29 : : #include <openssl/conf.h>
30 : : #include <openssl/bio.h>
31 : : #include <openssl/stack.h>
32 : : #include <openssl/objects.h>
33 : : #include <openssl/asn1.h>
34 : : #include <openssl/pem.h>
35 : : #include <openssl/evp.h>
36 : : #include <openssl/x509.h>
37 : : #include <openssl/x509v3.h>
38 : : #include <openssl/pkcs12.h>
39 : :
40 : : #define SMIME_INTERNALS /* we want also our internal helper functions */
41 : : #include "smimeutil.h"
42 : :
43 : : /* ----------------------- get info ----------------------- */
44 : :
45 : : /* Obtain some human readable descriptions of the certificate. This is
46 : : * important, for example, to verify if two certificates have the same
47 : : * public key modulus.
48 : : */
49 : :
50 : : /* Called by: smime_get_cert_info */
51 : : long /* return serial number, -1 on failure */
52 : : get_cert_info(X509* x509,
53 : : char** modulus, /* public key modulus */
54 : : char** fingerprint) /* finger print that identifies */
55 : 0 : {
56 : 0 : BIO* wbio = NULL;
57 [ # # ]: 0 : if (modulus) *modulus = NULL;
58 [ # # ]: 0 : if (fingerprint) *fingerprint = NULL;
59 [ # # ]: 0 : if (!x509) GOTO_ERR("NULL arg");
60 : :
61 : : /* Extract the public key part to be printed on paper */
62 : :
63 [ # # ]: 0 : if (modulus) {
64 : : EVP_PKEY* pubkey;
65 [ # # ]: 0 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
66 : :
67 : 0 : pubkey = X509_get_pubkey(x509);
68 : 0 : BN_print(wbio,pubkey->pkey.rsa->n);
69 [ # # ]: 0 : if (get_written_BIO_data(wbio, modulus) == -1) goto err;
70 : 0 : BIO_free_all(wbio);
71 : 0 : wbio = NULL;
72 : : }
73 : :
74 : : /* Extract conventional message digest */
75 : :
76 [ # # ]: 0 : if (fingerprint) {
77 : : unsigned int md_size;
78 : : unsigned char md[EVP_MAX_MD_SIZE];
79 [ # # ]: 0 : if (!X509_digest(x509,EVP_md5(),md,&md_size)) GOTO_ERR("X509_digest");
80 [ # # ]: 0 : if (!md_size) goto err;
81 [ # # ]: 0 : if (!(*fingerprint = smime_dotted_hex((char*)md,md_size))) goto err;
82 : : }
83 : 0 : return ASN1_INTEGER_get(x509->cert_info->serialNumber);
84 : 0 : err:
85 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
86 : 0 : return -1;
87 : : }
88 : :
89 : : /* Called by: main */
90 : : long /* return serial number, -1 on failure */
91 : : smime_get_cert_info(const char* x509_cert_pem,
92 : : char** modulus, /* public key modulus */
93 : : char** fingerprint) /* finger print that identifies */
94 : 0 : {
95 : 0 : long serial = -1;
96 : 0 : X509* x509 = NULL;
97 [ # # ]: 0 : if (modulus) *modulus = NULL;
98 [ # # ]: 0 : if (fingerprint) *fingerprint = NULL;
99 [ # # ]: 0 : if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
100 : 0 : serial = get_cert_info(x509, modulus, fingerprint);
101 : :
102 : 0 : err:
103 [ # # ]: 0 : if (x509) X509_free(x509);
104 : 0 : return serial;
105 : : }
106 : :
107 : : /* -------------------------------------- */
108 : :
109 : : /* Called by: get_req_hash, smime_get_req_modulus */
110 : : char* /* public key modulus */
111 : : get_req_modulus(X509_REQ* req)
112 : 0 : {
113 : 0 : char* modulus = NULL;
114 : 0 : BIO* wbio = NULL;
115 : : EVP_PKEY* pubkey;
116 : :
117 [ # # ]: 0 : if (!req) GOTO_ERR("NULL arg");
118 [ # # ]: 0 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
119 : :
120 : : /* Extract the public key part to be printed on paper */
121 : :
122 : 0 : pubkey = X509_REQ_get_pubkey(req);
123 : 0 : BN_print(wbio,pubkey->pkey.rsa->n);
124 [ # # ]: 0 : if (get_written_BIO_data(wbio, &modulus) == -1) goto err;
125 : 0 : BIO_free_all(wbio);
126 : 0 : return modulus;
127 : :
128 : 0 : err:
129 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
130 : 0 : return NULL;
131 : : }
132 : :
133 : : /* Called by: main */
134 : : char* /* public key modulus */
135 : : smime_get_req_modulus(const char* request_pem)
136 : 0 : {
137 : 0 : char* modulus = NULL;
138 : 0 : X509_REQ* req = NULL;;
139 [ # # ]: 0 : if (!(req = extract_request(request_pem))) goto err;
140 : 0 : modulus = get_req_modulus(req);
141 : :
142 : 0 : err:
143 [ # # ]: 0 : if (req) X509_REQ_free(req);
144 : 0 : return modulus;
145 : : }
146 : :
147 : : /* -------------------------------------- */
148 : :
149 : : /* Calculate a hash over any string (I use it for modulus) */
150 : :
151 : : /* Called by: main x2 */
152 : : char* /* returns the md5 hash as hex dump */
153 : : smime_md5(const char* data)
154 : 0 : {
155 : : EVP_MD_CTX ctx;
156 : : unsigned int md_size;
157 : : unsigned char md[EVP_MAX_MD_SIZE];
158 : :
159 : 0 : EVP_DigestInit(&ctx,EVP_md5());
160 : 0 : EVP_DigestUpdate(&ctx,data,strlen(data));
161 : 0 : EVP_DigestFinal(&ctx,md,&md_size);
162 : 0 : return smime_hex((char*)md, md_size);
163 : : }
164 : :
165 : : /* ---------- req hash ----------- */
166 : :
167 : : /* request hash is a 25 bit hash used for fast (but not necessarily
168 : : * collision free) identification and database queries. It has so few
169 : : * bits because it must fit on coarse 3 of 9 bar code. Basically
170 : : * 25 bits are encoded in 5 characters from alphabet of 32.
171 : :
172 : : Hashing scheme:
173 : : MD5(subject_DN . attributes . public_key_modulus) --> produces
174 : : 128 bits (16 bytes). Take first three bytes plus LSB of fourth
175 : : byte and encode them in base 32.
176 : :
177 : : On second thought, if we use two bar codes of 13+2 characters, we can
178 : : represent full 128 bits of information. This should be considered
179 : : sufficient even on security grounds. So, take 128 bit MD5 hash, divide
180 : : it in two blocks of 64 bits (8 bytes). Now, 13*5 = 65, so it takes
181 : : 13 characters to encode each block. Last bit is padded with zero.
182 : :
183 : : Base 32 encoding:
184 : : work from LSB to MSB and left to right in groups of 5 bits (5 groups),
185 : : encode each 5 bit number using
186 : :
187 : : 1 2 3
188 : : 01234567890123456789012345678901
189 : : key ==> "ZY234.6789ABCDEFGHWJKLMNXPQR-TUV" <==
190 : :
191 : :
192 : : Note: Difficult-to-distinguish characters in the sequence have
193 : : been replaced by less ambiguous ones: 0O1I5S --> ZXYW.-
194 : :
195 : : Note: LSB of first 5 bit number is LSB of byte 0. LSB of second 5 bit
196 : : number is bit 5 of byte 0 and MSB of second number is bit 1 of byte 1.
197 : :
198 : : <-- MSB LSB -->
199 : :
200 : : Char Pad
201 : : | byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 |
202 : : V AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG HHHHHHHH V
203 : : 0: 43210
204 : : 1: 210 43
205 : : 2: 43210
206 : : 3: 0 4321
207 : : 4: 3210 4
208 : : 5: 43210
209 : : 6: 01 423
210 : : 7: 43210
211 : : 8: 43210
212 : : 9: 210 43
213 : : 10: 43210
214 : : 11: 0 4321
215 : : 12: 3210 4
216 : :
217 : : */
218 : :
219 : : static char req_hash_key[] = "ZY234.6789ABCDEFGHWJKLMNXPQR-TUV";
220 : :
221 : : /* Called by: get_req_hash x2 */
222 : : static void
223 : : encode_64bits(unsigned char* md, char*p)
224 : 0 : {
225 : 0 : p[0] = req_hash_key[ md[0] & 0x1f ];
226 : 0 : p[1] = req_hash_key[ ((md[0] >> 5) & 0x07) | ((md[1] & 0x03) << 3) ];
227 : 0 : p[2] = req_hash_key[ (md[1] >> 2) & 0x1f ];
228 : 0 : p[3] = req_hash_key[ ((md[1] >> 7) & 0x01) | ((md[2] & 0x0f) << 1) ];
229 : 0 : p[4] = req_hash_key[ ((md[2] >> 4) & 0x0f) | ((md[3] & 0x01) << 4) ];
230 : 0 : p[5] = req_hash_key[ (md[3] >> 1) & 0x1f ];
231 : 0 : p[6] = req_hash_key[ ((md[3] >> 6) & 0x03) | ((md[4] & 0x07) << 2) ];
232 : 0 : p[7] = req_hash_key[ (md[4] >> 3) & 0x1f ];
233 : 0 : p[8] = req_hash_key[ md[5] & 0x1f ];
234 : 0 : p[9] = req_hash_key[ ((md[5] >> 5) & 0x07) | ((md[6] & 0x03) << 3) ];
235 : 0 : p[10] = req_hash_key[ (md[6] >> 2) & 0x1f ];
236 : 0 : p[11] = req_hash_key[ ((md[6] >> 7) & 0x01) | ((md[7] & 0x0f) << 1) ];
237 : 0 : p[12] = req_hash_key[ ((md[7] >> 4) & 0x0f) /* | bit4 is zero pad */ ];
238 : 0 : p[13] = '\0';
239 : 0 : }
240 : :
241 : : /* Called by: */
242 : : char* /* hash, ready to print, or NULL if error */
243 : : get_req_hash(X509_REQ* req)
244 : 0 : {
245 : : EVP_MD_CTX ctx;
246 : : unsigned int md_size;
247 : : unsigned char md[EVP_MAX_MD_SIZE];
248 : : char* p;
249 : :
250 [ # # ]: 0 : if (!req) GOTO_ERR("NULL arg");
251 : :
252 : 0 : EVP_DigestInit(&ctx,EVP_md5());
253 : :
254 [ # # ]: 0 : if (!(p = get_req_name(req))) goto err;
255 : 0 : EVP_DigestUpdate(&ctx,p,strlen(p));
256 : 0 : OPENSSL_free(p);
257 : :
258 [ # # ]: 0 : if (!(p = get_req_attr(req))) goto err;
259 : 0 : EVP_DigestUpdate(&ctx,p,strlen(p));
260 : 0 : OPENSSL_free(p);
261 : :
262 [ # # ]: 0 : if (!(p = get_req_modulus(req))) goto err;
263 : 0 : EVP_DigestUpdate(&ctx,p,strlen(p));
264 : 0 : OPENSSL_free(p);
265 : :
266 : 0 : EVP_DigestFinal(&ctx,md,&md_size);
267 : :
268 [ # # ]: 0 : if (md_size < 16) goto err;
269 [ # # ]: 0 : if (!(p = (char*)OPENSSL_malloc(13+13+1))) GOTO_ERR("no memory?");
270 : :
271 : 0 : encode_64bits(md, p); /* block 1, first 13 chars */
272 : 0 : encode_64bits(md+8, p+13); /* block 2, second 13 chars */
273 : 0 : return p;
274 : :
275 : 0 : err:
276 : 0 : return NULL;
277 : : }
278 : :
279 : : char* /* 25 bit hash as string like `*Z4K67W*' or NULL if error */
280 : : smime_get_req_hash(const char* request_pem)
281 : 0 : {
282 : 0 : char* n = NULL;
283 : 0 : X509_REQ* req = NULL;
284 [ # # ]: 0 : if (!(req = extract_request(request_pem))) goto err;
285 : 0 : n = get_req_hash(req);
286 : :
287 : 0 : err:
288 [ # # ]: 0 : if (req) X509_REQ_free(req);
289 : 0 : return n;
290 : : }
291 : :
292 : : /* -------------------------------------- */
293 : :
294 : : /* Get distinguished name information from the certificate */
295 : :
296 : : /* Called by: smime_get_cert_names */
297 : : long /* return serial number, -1 on failure */
298 : : get_cert_names(X509* x509,
299 : : char** subject_DN, /* who the certificate belongs to */
300 : : char** issuer_DN) /* who signed the certificate */
301 : 0 : {
302 : 0 : long serial = -1;
303 : :
304 [ # # ]: 0 : if (subject_DN) *subject_DN = NULL;
305 [ # # ]: 0 : if (issuer_DN) *issuer_DN = NULL;
306 [ # # ]: 0 : if (!x509) GOTO_ERR("NULL arg");
307 : :
308 [ # # ]: 0 : if (subject_DN) { /* if you don't want to know subject, pass this as NULL */
309 [ # # ]: 0 : if (!(*subject_DN = X509_NAME_oneline(X509_get_subject_name(x509),NULL,0)))
310 : 0 : GOTO_ERR("no memory?");
311 : : }
312 : :
313 [ # # ]: 0 : if (issuer_DN) { /* if you don't want to know issuer, pass NULL here */
314 [ # # ]: 0 : if (!(*issuer_DN = X509_NAME_oneline(X509_get_issuer_name(x509),NULL,0)))
315 : 0 : GOTO_ERR("no memory?");
316 : : }
317 : :
318 : : /* extract serial number */
319 : :
320 : 0 : serial = ASN1_INTEGER_get(x509->cert_info->serialNumber);
321 : 0 : err:
322 : 0 : return serial;
323 : : }
324 : :
325 : : /* Called by: main */
326 : : long /* return serial number, -1 on failure */
327 : : smime_get_cert_names(const char* x509_cert_pem,
328 : : char** subject_DN, /* who the certificate belongs to */
329 : : char** issuer_DN) /* who signed the certificate */
330 : 1 : {
331 : 1 : long serial = -1;
332 : 1 : X509* x509 = NULL;
333 [ + - ]: 1 : if (subject_DN) *subject_DN = NULL;
334 [ + - ]: 1 : if (issuer_DN) *issuer_DN = NULL;
335 [ - + ]: 1 : if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
336 : 0 : serial = get_cert_names(x509, subject_DN, issuer_DN);
337 : :
338 : 1 : err:
339 [ - + ]: 1 : if (x509) X509_free(x509);
340 : 1 : return serial;
341 : : }
342 : :
343 : : /* -------------------------------------- */
344 : :
345 : : /* Getting the attributes does not appear to be too well supported, i.e.
346 : : * there is no easy way. You just have to walk the data structure yourself.
347 : : * This function only understands sets of one value and single values.
348 : : * See crypto/asn1/asn1_par.c for similar code. */
349 : :
350 : : /* Called by: get_req_hash, smime_get_req_attr */
351 : : char* /* new line separated list of attribute value pairs */
352 : : get_req_attr(X509_REQ* req)
353 : 0 : {
354 : : int i;
355 : 0 : STACK_OF(X509_ATTRIBUTE)* xas = NULL;
356 : : X509_ATTRIBUTE* xa;
357 : : ASN1_TYPE* val;
358 : 0 : STACK_OF(ASN1_TYPE)* vals = NULL;
359 : 0 : char* buf = NULL;
360 : :
361 [ # # ]: 0 : if (!req) GOTO_ERR("NULL arg");
362 [ # # ]: 0 : if (!(buf = strdup(""))) GOTO_ERR("no memory?");
363 [ # # ]: 0 : if ((xas = req->req_info->attributes) == NULL) goto err; /* no attributes */
364 : :
365 [ # # ]: 0 : for (i = 0; i < sk_X509_ATTRIBUTE_num(xas); i++) {
366 : 0 : xa = sk_X509_ATTRIBUTE_value(xas, i);
367 : :
368 : : /* print the (long)name of the attribute */
369 : :
370 [ # # ]: 0 : if (!(buf = concat(buf, OBJ_nid2ln(OBJ_obj2nid(xa->object))))) goto err;
371 [ # # ]: 0 : if (!(buf = concat(buf, "="))) goto err;
372 : :
373 : : /* Obtain either the single value or the first value in the set */
374 : :
375 : : if (1 /*|| xa->single **** this is called set on some versions */) {
376 [ # # # # ]: 0 : if ((vals = xa->value.set) && sk_ASN1_TYPE_num(vals)) {
377 : 0 : val = sk_ASN1_TYPE_value(vals,0);
378 : : } else
379 : 0 : val = NULL;
380 : : } else {
381 : : val = xa->value.single;
382 : : }
383 [ # # ]: 0 : if (val) {
384 : : /* print the value. *** for now this only works for various string
385 : : types */
386 [ # # ]: 0 : if (!(buf = concatmem(buf, (char*)(val->value.asn1_string->data),
387 : 0 : val->value.asn1_string->length))) goto err;
388 : : }
389 : :
390 [ # # ]: 0 : if (!(buf = concat(buf,"\n"))) goto err;
391 : : }
392 : 0 : return buf;
393 : 0 : err:
394 : 0 : return NULL;
395 : : }
396 : :
397 : : /* Called by: main */
398 : : char* /* public key modulus */
399 : : smime_get_req_attr(const char* request_pem)
400 : 0 : {
401 : 0 : char* name = NULL;
402 : 0 : X509_REQ* req = NULL;
403 [ # # ]: 0 : if (!(req = extract_request(request_pem))) goto err;
404 : 0 : name = get_req_attr(req);
405 : :
406 : 0 : err:
407 [ # # ]: 0 : if (req) X509_REQ_free(req);
408 : 0 : return name;
409 : : }
410 : :
411 : : /* Called by: get_req_hash, smime_get_req_name */
412 : : char* /* subject_DN - who the request belongs to */
413 : : get_req_name(X509_REQ* req)
414 : 0 : {
415 [ # # ]: 0 : if (!req) GOTO_ERR("NULL arg");
416 : 0 : return X509_NAME_oneline(X509_REQ_get_subject_name(req),NULL,0);
417 : 0 : err:
418 : 0 : return NULL;
419 : : }
420 : :
421 : : /* Called by: main */
422 : : char* /* public key modulus */
423 : : smime_get_req_name(const char* request_pem)
424 : 1 : {
425 : 1 : char* name = NULL;
426 : 1 : X509_REQ* req = NULL;
427 [ - + ]: 1 : if (!(req = extract_request(request_pem))) goto err;
428 : 0 : name = get_req_name(req);
429 : :
430 : 1 : err:
431 [ - + ]: 1 : if (req) X509_REQ_free(req);
432 : 1 : return name;
433 : : }
434 : :
435 : : /* EOF - smime-qry.c */
|