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 */
get_cert_info(X509 * x509,char ** modulus,char ** fingerprint)52 get_cert_info(X509* x509,
53 char** modulus, /* public key modulus */
54 char** fingerprint) /* finger print that identifies */
55 {
56 BIO* wbio = NULL;
57 if (modulus) *modulus = NULL;
58 if (fingerprint) *fingerprint = NULL;
59 if (!x509) GOTO_ERR("NULL arg");
60
61 /* Extract the public key part to be printed on paper */
62
63 if (modulus) {
64 EVP_PKEY* pubkey;
65 if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
66
67 pubkey = X509_get_pubkey(x509);
68 BN_print(wbio,pubkey->pkey.rsa->n);
69 if (get_written_BIO_data(wbio, modulus) == -1) goto err;
70 BIO_free_all(wbio);
71 wbio = NULL;
72 }
73
74 /* Extract conventional message digest */
75
76 if (fingerprint) {
77 unsigned int md_size;
78 unsigned char md[EVP_MAX_MD_SIZE];
79 if (!X509_digest(x509,EVP_md5(),md,&md_size)) GOTO_ERR("X509_digest");
80 if (!md_size) goto err;
81 if (!(*fingerprint = smime_dotted_hex((char*)md,md_size))) goto err;
82 }
83 return ASN1_INTEGER_get(x509->cert_info->serialNumber);
84 err:
85 if (wbio) BIO_free_all(wbio);
86 return -1;
87 }
88
89 /* Called by: main */
90 long /* return serial number, -1 on failure */
smime_get_cert_info(const char * x509_cert_pem,char ** modulus,char ** fingerprint)91 smime_get_cert_info(const char* x509_cert_pem,
92 char** modulus, /* public key modulus */
93 char** fingerprint) /* finger print that identifies */
94 {
95 long serial = -1;
96 X509* x509 = NULL;
97 if (modulus) *modulus = NULL;
98 if (fingerprint) *fingerprint = NULL;
99 if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
100 serial = get_cert_info(x509, modulus, fingerprint);
101
102 err:
103 if (x509) X509_free(x509);
104 return serial;
105 }
106
107 /* -------------------------------------- */
108
109 /* Called by: get_req_hash, smime_get_req_modulus */
110 char* /* public key modulus */
get_req_modulus(X509_REQ * req)111 get_req_modulus(X509_REQ* req)
112 {
113 char* modulus = NULL;
114 BIO* wbio = NULL;
115 EVP_PKEY* pubkey;
116
117 if (!req) GOTO_ERR("NULL arg");
118 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 pubkey = X509_REQ_get_pubkey(req);
123 BN_print(wbio,pubkey->pkey.rsa->n);
124 if (get_written_BIO_data(wbio, &modulus) == -1) goto err;
125 BIO_free_all(wbio);
126 return modulus;
127
128 err:
129 if (wbio) BIO_free_all(wbio);
130 return NULL;
131 }
132
133 /* Called by: main */
134 char* /* public key modulus */
smime_get_req_modulus(const char * request_pem)135 smime_get_req_modulus(const char* request_pem)
136 {
137 char* modulus = NULL;
138 X509_REQ* req = NULL;;
139 if (!(req = extract_request(request_pem))) goto err;
140 modulus = get_req_modulus(req);
141
142 err:
143 if (req) X509_REQ_free(req);
144 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 */
smime_md5(const char * data)153 smime_md5(const char* data)
154 {
155 EVP_MD_CTX ctx;
156 unsigned int md_size;
157 unsigned char md[EVP_MAX_MD_SIZE];
158
159 EVP_DigestInit(&ctx,EVP_md5());
160 EVP_DigestUpdate(&ctx,data,strlen(data));
161 EVP_DigestFinal(&ctx,md,&md_size);
162 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
encode_64bits(unsigned char * md,char * p)223 encode_64bits(unsigned char* md, char*p)
224 {
225 p[0] = req_hash_key[ md[0] & 0x1f ];
226 p[1] = req_hash_key[ ((md[0] >> 5) & 0x07) | ((md[1] & 0x03) << 3) ];
227 p[2] = req_hash_key[ (md[1] >> 2) & 0x1f ];
228 p[3] = req_hash_key[ ((md[1] >> 7) & 0x01) | ((md[2] & 0x0f) << 1) ];
229 p[4] = req_hash_key[ ((md[2] >> 4) & 0x0f) | ((md[3] & 0x01) << 4) ];
230 p[5] = req_hash_key[ (md[3] >> 1) & 0x1f ];
231 p[6] = req_hash_key[ ((md[3] >> 6) & 0x03) | ((md[4] & 0x07) << 2) ];
232 p[7] = req_hash_key[ (md[4] >> 3) & 0x1f ];
233 p[8] = req_hash_key[ md[5] & 0x1f ];
234 p[9] = req_hash_key[ ((md[5] >> 5) & 0x07) | ((md[6] & 0x03) << 3) ];
235 p[10] = req_hash_key[ (md[6] >> 2) & 0x1f ];
236 p[11] = req_hash_key[ ((md[6] >> 7) & 0x01) | ((md[7] & 0x0f) << 1) ];
237 p[12] = req_hash_key[ ((md[7] >> 4) & 0x0f) /* | bit4 is zero pad */ ];
238 p[13] = '\0';
239 }
240
241 /* Called by: */
242 char* /* hash, ready to print, or NULL if error */
get_req_hash(X509_REQ * req)243 get_req_hash(X509_REQ* req)
244 {
245 EVP_MD_CTX ctx;
246 unsigned int md_size;
247 unsigned char md[EVP_MAX_MD_SIZE];
248 char* p;
249
250 if (!req) GOTO_ERR("NULL arg");
251
252 EVP_DigestInit(&ctx,EVP_md5());
253
254 if (!(p = get_req_name(req))) goto err;
255 EVP_DigestUpdate(&ctx,p,strlen(p));
256 OPENSSL_free(p);
257
258 if (!(p = get_req_attr(req))) goto err;
259 EVP_DigestUpdate(&ctx,p,strlen(p));
260 OPENSSL_free(p);
261
262 if (!(p = get_req_modulus(req))) goto err;
263 EVP_DigestUpdate(&ctx,p,strlen(p));
264 OPENSSL_free(p);
265
266 EVP_DigestFinal(&ctx,md,&md_size);
267
268 if (md_size < 16) goto err;
269 if (!(p = (char*)OPENSSL_malloc(13+13+1))) GOTO_ERR("no memory?");
270
271 encode_64bits(md, p); /* block 1, first 13 chars */
272 encode_64bits(md+8, p+13); /* block 2, second 13 chars */
273 return p;
274
275 err:
276 return NULL;
277 }
278
279 char* /* 25 bit hash as string like `*Z4K67W*' or NULL if error */
smime_get_req_hash(const char * request_pem)280 smime_get_req_hash(const char* request_pem)
281 {
282 char* n = NULL;
283 X509_REQ* req = NULL;
284 if (!(req = extract_request(request_pem))) goto err;
285 n = get_req_hash(req);
286
287 err:
288 if (req) X509_REQ_free(req);
289 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 */
get_cert_names(X509 * x509,char ** subject_DN,char ** issuer_DN)298 get_cert_names(X509* x509,
299 char** subject_DN, /* who the certificate belongs to */
300 char** issuer_DN) /* who signed the certificate */
301 {
302 long serial = -1;
303
304 if (subject_DN) *subject_DN = NULL;
305 if (issuer_DN) *issuer_DN = NULL;
306 if (!x509) GOTO_ERR("NULL arg");
307
308 if (subject_DN) { /* if you don't want to know subject, pass this as NULL */
309 if (!(*subject_DN = X509_NAME_oneline(X509_get_subject_name(x509),NULL,0)))
310 GOTO_ERR("no memory?");
311 }
312
313 if (issuer_DN) { /* if you don't want to know issuer, pass NULL here */
314 if (!(*issuer_DN = X509_NAME_oneline(X509_get_issuer_name(x509),NULL,0)))
315 GOTO_ERR("no memory?");
316 }
317
318 /* extract serial number */
319
320 serial = ASN1_INTEGER_get(x509->cert_info->serialNumber);
321 err:
322 return serial;
323 }
324
325 /* Called by: main */
326 long /* return serial number, -1 on failure */
smime_get_cert_names(const char * x509_cert_pem,char ** subject_DN,char ** issuer_DN)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 {
331 long serial = -1;
332 X509* x509 = NULL;
333 if (subject_DN) *subject_DN = NULL;
334 if (issuer_DN) *issuer_DN = NULL;
335 if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
336 serial = get_cert_names(x509, subject_DN, issuer_DN);
337
338 err:
339 if (x509) X509_free(x509);
340 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 */
get_req_attr(X509_REQ * req)352 get_req_attr(X509_REQ* req)
353 {
354 int i;
355 STACK_OF(X509_ATTRIBUTE)* xas = NULL;
356 X509_ATTRIBUTE* xa;
357 ASN1_TYPE* val;
358 STACK_OF(ASN1_TYPE)* vals = NULL;
359 char* buf = NULL;
360
361 if (!req) GOTO_ERR("NULL arg");
362 if (!(buf = strdup(""))) GOTO_ERR("no memory?");
363 if ((xas = req->req_info->attributes) == NULL) goto err; /* no attributes */
364
365 for (i = 0; i < sk_X509_ATTRIBUTE_num(xas); i++) {
366 xa = sk_X509_ATTRIBUTE_value(xas, i);
367
368 /* print the (long)name of the attribute */
369
370 if (!(buf = concat(buf, OBJ_nid2ln(OBJ_obj2nid(xa->object))))) goto err;
371 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 if ((vals = xa->value.set) && sk_ASN1_TYPE_num(vals)) {
377 val = sk_ASN1_TYPE_value(vals,0);
378 } else
379 val = NULL;
380 } else {
381 val = xa->value.single;
382 }
383 if (val) {
384 /* print the value. *** for now this only works for various string
385 types */
386 if (!(buf = concatmem(buf, (char*)(val->value.asn1_string->data),
387 val->value.asn1_string->length))) goto err;
388 }
389
390 if (!(buf = concat(buf,"\n"))) goto err;
391 }
392 return buf;
393 err:
394 return NULL;
395 }
396
397 /* Called by: main */
398 char* /* public key modulus */
smime_get_req_attr(const char * request_pem)399 smime_get_req_attr(const char* request_pem)
400 {
401 char* name = NULL;
402 X509_REQ* req = NULL;
403 if (!(req = extract_request(request_pem))) goto err;
404 name = get_req_attr(req);
405
406 err:
407 if (req) X509_REQ_free(req);
408 return name;
409 }
410
411 /* Called by: get_req_hash, smime_get_req_name */
412 char* /* subject_DN - who the request belongs to */
get_req_name(X509_REQ * req)413 get_req_name(X509_REQ* req)
414 {
415 if (!req) GOTO_ERR("NULL arg");
416 return X509_NAME_oneline(X509_REQ_get_subject_name(req),NULL,0);
417 err:
418 return NULL;
419 }
420
421 /* Called by: main */
422 char* /* public key modulus */
smime_get_req_name(const char * request_pem)423 smime_get_req_name(const char* request_pem)
424 {
425 char* name = NULL;
426 X509_REQ* req = NULL;
427 if (!(req = extract_request(request_pem))) goto err;
428 name = get_req_name(req);
429
430 err:
431 if (req) X509_REQ_free(req);
432 return name;
433 }
434
435 /* EOF - smime-qry.c */
436