Branch data Line data Source code
1 : : /* smime-vfy.c - Utility functions for performing S/MIME signature
2 : : * verification and decryption.
3 : : *
4 : : * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
5 : : * License: This software may be distributed under the same license
6 : : * terms as openssl (i.e. free, but mandatory attribution).
7 : : * See file LICENSE for details.
8 : : *
9 : : * 11.9.1999, Created. --Sampo
10 : : * 13.9.1999, 0.1 released. Now adding verify. --Sampo
11 : : * 1.10.1999, improved error handling, fixed decrypt --Sampo
12 : : * 6.10.1999, separated from smimeutil.c --Sampo
13 : : * 9.10.1999, fixed double free in decryption --Sampo
14 : : * 14.11.1999, added verification of detached sigs, i.e. clear sigs --Sampo
15 : : *
16 : : * This module has adopted ideas and control flow from
17 : : * openssl-0.9.4/crypto/pkcs7/sign.c
18 : : * openssl-0.9.4/crypto/pkcs7/verify.c
19 : : * openssl-0.9.4/crypto/pkcs7/enc.c
20 : : * openssl-0.9.4/crypto/pkcs7/dec.c
21 : : * which are Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com),
22 : : * All rights reserved. See file LICENSE for conditions.
23 : : *
24 : : * This module has been developed to support a Lingo XTRA that is supposed
25 : : * to provide crypto functionality. It may, however, be useful for other
26 : : * purposes as well.
27 : : *
28 : : * This is a very simple S/MIME library. For example the multipart
29 : : * boundary separators are hard coded and no effort is made to verify
30 : : * that mime entities are in their canonical form before signing (the
31 : : * caller should make sure they are, canonical form means using CRLF
32 : : * as line termination, among other things). Also the multipart functionality
33 : : * only understands up to 3 attachments. For many tasks this is enough,
34 : : * but if its not, feel free to write more generic utilities.
35 : : *
36 : : * Memory management: most routines malloc the results. Freeing them is
37 : : * application's responsibility. I use libc malloc, but if in doubt
38 : : * it might be safer to just leak the memory (i.e. don't ever free it).
39 : : * This library works entirely in memory, so maximum memory consumption
40 : : * might be more than twice the total size of all files to be encrypted.
41 : : */
42 : :
43 : : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
44 : : * All rights reserved.
45 : : *
46 : : * This package is an SSL implementation written
47 : : * by Eric Young (eay@cryptsoft.com).
48 : : * The implementation was written so as to conform with Netscapes SSL.
49 : : *
50 : : * This library is free for commercial and non-commercial use as long as
51 : : * the following conditions are aheared to. The following conditions
52 : : * apply to all code found in this distribution, be it the RC4, RSA,
53 : : * lhash, DES, etc., code; not just the SSL code. The SSL documentation
54 : : * included with this distribution is covered by the same copyright terms
55 : : * except that the holder is Tim Hudson (tjh@cryptsoft.com).
56 : : *
57 : : * Copyright remains Eric Young's, and as such any Copyright notices in
58 : : * the code are not to be removed.
59 : : * If this package is used in a product, Eric Young should be given attribution
60 : : * as the author of the parts of the library used.
61 : : * This can be in the form of a textual message at program startup or
62 : : * in documentation (online or textual) provided with the package.
63 : : *
64 : : * Redistribution and use in source and binary forms, with or without
65 : : * modification, are permitted provided that the following conditions
66 : : * are met:
67 : : * 1. Redistributions of source code must retain the copyright
68 : : * notice, this list of conditions and the following disclaimer.
69 : : * 2. Redistributions in binary form must reproduce the above copyright
70 : : * notice, this list of conditions and the following disclaimer in the
71 : : * documentation and/or other materials provided with the distribution.
72 : : * 3. All advertising materials mentioning features or use of this software
73 : : * must display the following acknowledgement:
74 : : * "This product includes cryptographic software written by
75 : : * Eric Young (eay@cryptsoft.com)"
76 : : * The word 'cryptographic' can be left out if the rouines from the library
77 : : * being used are not cryptographic related :-).
78 : : * 4. If you include any Windows specific code (or a derivative thereof) from
79 : : * the apps directory (application code) you must include an acknowledgement:
80 : : * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
81 : : *
82 : : * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
83 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
86 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
92 : : * SUCH DAMAGE.
93 : : *
94 : : * The licence and distribution terms for any publically available version or
95 : : * derivative of this code cannot be changed. i.e. this code cannot simply be
96 : : * copied and put under another distribution licence
97 : : * [including the GNU Public Licence.]
98 : : */
99 : :
100 : : #include "platform.h"
101 : :
102 : : #include <stdlib.h>
103 : : #include <string.h>
104 : : #include <time.h>
105 : :
106 : : #if defined(macintosh) || defined(__INTEL__)
107 : : #include "macglue.h"
108 : : #endif
109 : :
110 : : #include "logprint.h"
111 : :
112 : : #include <openssl/crypto.h>
113 : : #include <openssl/buffer.h>
114 : : #include <openssl/stack.h>
115 : : #include <openssl/bio.h>
116 : : #include <openssl/x509.h>
117 : : #include <openssl/pem.h>
118 : : #include <openssl/err.h>
119 : :
120 : : #define SMIME_INTERNALS /* we want also our internal helper functions */
121 : : #include "smimeutil.h"
122 : :
123 : : /* ============= S I G N A T U R E V E R I F I C A T I O N ============== */
124 : : /* ==================== A N D D E C R Y P T I O N ======================= */
125 : :
126 : : /* Called by: decrypt, smime_get_signer_info, smime_verify_signature */
127 : : static PKCS7*
128 : : get_pkcs7_from_pem(const char* enc_entity)
129 : 3 : {
130 : : const char* p;
131 : 3 : char* wrapped_enc_entity = NULL;
132 : 3 : BIO* rbio = NULL;
133 : 3 : PKCS7* p7 = NULL;
134 : :
135 : : /* Check if encrypted entity is composed of raw data or if it has some
136 : : * headers. In the latter case, just skip the headers. Headers are
137 : : * separated from data by an empty line (hence sequence CRLF CRLF).*/
138 : :
139 [ - + ]: 3 : if ((p = strstr(enc_entity, CRLF CRLF))) {
140 : 0 : enc_entity = p+4;
141 [ + + ]: 3 : } else if ((p = strstr(enc_entity, LF LF))) {
142 : 1 : enc_entity = p+2;
143 [ - + ]: 2 : } else if ((p = strstr(enc_entity, CR CR))) {
144 : 0 : enc_entity = p+2;
145 : : }
146 : :
147 : : /* Make sure the pem markers are there */
148 : :
149 : : LOG_PRINT("get_pkcs7_from_pem: wrapping in pem markers");
150 : :
151 [ - + ]: 3 : if (!(wrapped_enc_entity = wrap_in_pem_markers(enc_entity, "PKCS7")))
152 : 0 : GOTO_ERR("no memory?");
153 : : LOG_PRINT("get_pkcs7_from_pem: wrapped.");
154 : :
155 : : /* Set up BIO so encrypted/signed data can be read from pem file */
156 : :
157 [ + - ]: 3 : if (!(rbio = set_read_BIO_from_buf(wrapped_enc_entity, -1))) goto err;
158 : :
159 : : LOG_PRINT("get_pkcs7_from_pem: ready to read PKCS7 bio...");
160 : :
161 : : /* Load the PKCS7 object from a pem file to internal representation.
162 : : * this reads all of the data file. */
163 : :
164 [ + - ]: 3 : if (!(p7=PEM_read_bio_PKCS7(rbio,NULL/*&x*/,NULL/*callback*/,NULL/*arg*/)))
165 : 3 : GOTO_ERR("11 corrupt PEM PKCS7 file? (PEM_read_bio_PKCS7)");
166 : :
167 : : LOG_PRINT("get_pkcs7_from_pem: bio read");
168 : :
169 : 0 : BIO_free_all(rbio);
170 : 0 : OPENSSL_free(wrapped_enc_entity);
171 : 0 : return p7;
172 : 3 : err:
173 [ + - ]: 3 : if (rbio) BIO_free_all(rbio);
174 [ + - ]: 3 : if (wrapped_enc_entity) OPENSSL_free(wrapped_enc_entity);
175 : 3 : return NULL;
176 : : }
177 : :
178 : : /* Typically receiver has to know in what order the signature and encryption
179 : : * were applied (usually encryption is outermost) and then call these
180 : : * functions in right order, e.g:
181 : : */
182 : :
183 : : /* Called by: smime_decrypt */
184 : : int /* return size of data, -1 on failure */
185 : : decrypt(X509* x509, EVP_PKEY* pkey, const char* enc_entity, char** data_out)
186 : 0 : {
187 : : char buf[4096];
188 : : int i,n;
189 : 0 : BIO* wbio = NULL;
190 : 0 : BIO* p7bio = NULL;
191 : 0 : PKCS7 *p7 = NULL;
192 : :
193 [ # # ]: 0 : if (data_out) *data_out = NULL;
194 [ # # # # : 0 : if (!x509 || !pkey || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
# # # # ]
195 : : LOG_PRINT("decrypt: get_pkcs7_from_pem");
196 [ # # ]: 0 : if (!(p7 = get_pkcs7_from_pem(enc_entity))) goto err;
197 : :
198 : : /* Decrypt the symmetric key with private key and obtain symmetric
199 : : * cipher stream (BIO). The cert is needed here to look up one of
200 : : * possibly multiple recipient infos present in PKCS7 object. Issuer
201 : : * and serial number must match (these two fields form unique ID for
202 : : * cert). Actual public key part of the X509 cert is not used for
203 : : * anything here. */
204 : :
205 : : LOG_PRINT("decrypt: dataDecode");
206 [ # # ]: 0 : if (!(p7bio=PKCS7_dataDecode(p7,pkey,NULL/*detached*/,x509)))
207 : 0 : GOTO_ERR("12 no recipient matches cert or private key could not decrypt, i.e. wrong key (PKCS7_dataDecode)");
208 : : LOG_PRINT("decrypt: ready to pump");
209 : :
210 : : /* Pump data from p7bio to decrypt symmetric cipher */
211 : :
212 [ # # ]: 0 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
213 : :
214 : : for (;;) {
215 [ # # ]: 0 : if ((i=BIO_read(p7bio,buf,sizeof(buf))) <= 0) break;
216 : 0 : BIO_write(wbio,buf,i);
217 : 0 : }
218 : 0 : BIO_flush(wbio);
219 : 0 : BIO_free_all(p7bio);
220 : 0 : p7bio = NULL;
221 : 0 : PKCS7_free(p7);
222 : 0 : p7 = NULL;
223 : :
224 : : LOG_PRINT("decrypt: pump done");
225 : :
226 : : /* Return data (this should now be easier because we just freed
227 : : * some memory) */
228 : :
229 : 0 : n = get_written_BIO_data(wbio, data_out);
230 : 0 : BIO_free_all(wbio);
231 : 0 : return n;
232 : :
233 : 0 : err:
234 [ # # ]: 0 : if (p7) PKCS7_free(p7);
235 [ # # ]: 0 : if (wbio) BIO_free_all(wbio);
236 [ # # ]: 0 : if (p7bio) BIO_free_all(p7bio);
237 : 0 : return -1;
238 : : }
239 : :
240 : : /* Called by: main */
241 : : int /* return size of data, -1 on failure */
242 : : smime_decrypt(const char* privkey,
243 : : const char* passwd,
244 : : const char* enc_entity,
245 : : char** data_out)
246 : 1 : {
247 : 1 : int n = -1;
248 : 1 : EVP_PKEY *pkey = NULL;
249 : 1 : X509 *x509 = NULL;
250 : :
251 [ + - ]: 1 : if (data_out) *data_out = NULL;
252 [ + - + - : 1 : if (!privkey || !passwd || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
+ - - + ]
253 [ - + ]: 1 : if (!(pkey = open_private_key(privkey, passwd))) goto err;
254 [ # # ]: 0 : if (!(x509 = extract_certificate(privkey))) goto err;
255 : 0 : n = decrypt(x509, pkey, enc_entity, data_out);
256 : :
257 : 1 : err:
258 [ - + ]: 1 : if (pkey) EVP_PKEY_free(pkey);
259 [ - + ]: 1 : if (x509) X509_free(x509);
260 : 1 : return n;
261 : : }
262 : :
263 : : /* ------------------------------------------------ */
264 : :
265 : : #if 0
266 : : /* copied from verify.c */
267 : : /* should be X509* but we can just have them as char*. (??? --Sampo) */
268 : : /* Called by: */
269 : : static int
270 : : verify_callback(int ok, X509_STORE_CTX *ctx) {
271 : : char buf[256];
272 : : X509 *err_cert;
273 : : int err,depth;
274 : :
275 : : err_cert=X509_STORE_CTX_get_current_cert(ctx);
276 : : err= X509_STORE_CTX_get_error(ctx);
277 : : depth= X509_STORE_CTX_get_error_depth(ctx);
278 : :
279 : : X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
280 : : fprintf(stderr,"depth=%d %s\n",depth,buf);
281 : : if (!ok) {
282 : : fprintf(stderr,"verify error:num=%d:%s\n",err,
283 : : X509_verify_cert_error_string(err));
284 : : if (depth < 6) {
285 : : ok=1;
286 : : X509_STORE_CTX_set_error(ctx,X509_V_OK);
287 : : } else {
288 : : ok=0;
289 : : X509_STORE_CTX_set_error(ctx,X509_V_ERR_CERT_CHAIN_TOO_LONG);
290 : : }
291 : : }
292 : : switch (ctx->error) {
293 : : case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
294 : : X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,sizeof(buf));
295 : : fprintf(stderr,"issuer= %s\n",buf);
296 : : break;
297 : : #if 1
298 : : case X509_V_ERR_CERT_NOT_YET_VALID:
299 : : case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
300 : : fprintf(stderr,"notBefore=");
301 : : /*ASN1_UTCTIME_print(bio_err,X509_get_notBefore(ctx->current_cert));
302 : : BIO_printf(bio_err,"\n");*/
303 : : break;
304 : : case X509_V_ERR_CERT_HAS_EXPIRED:
305 : : case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
306 : : fprintf(stderr,"notAfter=");
307 : : /*ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ctx->current_cert));
308 : : BIO_printf(bio_err,"\n"); */
309 : : break;
310 : : #endif
311 : : }
312 : : fprintf(stderr,"verify return:%d\n",ok);
313 : : return(ok);
314 : : }
315 : :
316 : : static int signed_seq2string_nid= -1;
317 : : /* For this case, I will malloc the return strings */
318 : : /* Called by: smime_verify_signature */
319 : : static int
320 : : get_signed_seq2string(PKCS7_SIGNER_INFO *si, char **str1, char **str2) {
321 : : #if 0
322 : : ASN1_TYPE *so;
323 : : if (signed_seq2string_nid == -1)
324 : : signed_seq2string_nid=
325 : : OBJ_create("1.9.9999","OID_example","Our example OID");
326 : : /* To retrieve */
327 : : so=PKCS7_get_signed_attribute(si,signed_seq2string_nid);
328 : : if (so && (so->type == V_ASN1_SEQUENCE))
329 : : {
330 : : ASN1_CTX c;
331 : : ASN1_STRING *s;
332 : : long length;
333 : : ASN1_OCTET_STRING *os1,*os2;
334 : :
335 : : s=so->value.sequence;
336 : : c.p=ASN1_STRING_data(s);
337 : : c.max=c.p+ASN1_STRING_length(s);
338 : : if (!asn1_GetSequence(&c,&length)) GOTO_ERR("") err;
339 : : /* Length is the length of the seqence */
340 : :
341 : : c.q=c.p;
342 : : if ((os1=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)
343 : : GOTO_ERR("");
344 : : c.slen-=(c.p-c.q);
345 : :
346 : : c.q=c.p;
347 : : if ((os2=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL)
348 : : GOTO_ERR("");
349 : : c.slen-=(c.p-c.q);
350 : :
351 : : if (!asn1_Finish(&c)) GOTO_ERR("") err;
352 : : *str1=Malloc(os1->length+1);
353 : : *str2=Malloc(os2->length+1);
354 : : memcpy(*str1,os1->data,os1->length);
355 : : memcpy(*str2,os2->data,os2->length);
356 : : (*str1)[os1->length]='\0';
357 : : (*str2)[os2->length]='\0';
358 : : ASN1_OCTET_STRING_free(os1);
359 : : ASN1_OCTET_STRING_free(os2);
360 : : return(1);
361 : : }
362 : : err:
363 : : #endif
364 : : return(0);
365 : : }
366 : : #endif
367 : :
368 : : /* Called by: main */
369 : : long /* return serial on success, -1 on failure */
370 : : smime_get_signer_info(const char* signed_entity,
371 : : int info_ix, /* 0 = first signer */
372 : : char** issuer) /* DN of the issuer */
373 : 1 : {
374 : 1 : int serial = -1;
375 : 1 : PKCS7* p7 = NULL;
376 : 1 : STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
377 : : PKCS7_SIGNER_INFO* si;
378 : :
379 [ + - - + ]: 1 : if (!signed_entity || !issuer) GOTO_ERR("NULL arg(s)");
380 : 1 : *issuer = NULL;
381 : :
382 [ - + ]: 1 : if (!(p7 = get_pkcs7_from_pem(signed_entity))) goto err;
383 [ # # ]: 0 : if (!(sigs=PKCS7_get_signer_info(p7)))
384 : 0 : GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
385 : :
386 [ # # ]: 0 : if (info_ix >= sk_PKCS7_SIGNER_INFO_num(sigs))
387 : 0 : GOTO_ERR("No more signers. info_ix too large.");
388 : :
389 [ # # ]: 0 : if (!(si=sk_PKCS7_SIGNER_INFO_value(sigs,info_ix)))
390 : 0 : GOTO_ERR("NULL signer info");
391 : :
392 : 0 : *issuer = X509_NAME_oneline(si->issuer_and_serial->issuer, NULL,0);
393 : 0 : serial = ASN1_INTEGER_get(si->issuer_and_serial->serial);
394 : :
395 : 1 : err:
396 [ - + ]: 1 : if (p7) PKCS7_free(p7);
397 : 1 : return serial;
398 : : }
399 : :
400 : : /* Called by: main x3 */
401 : : char* /* returns contents of the signed message, NULL if error */
402 : : smime_verify_signature(const char* pubkey,
403 : : const char* sig_entity, /* signed entity
404 : : or just the sigature */
405 : : const char* detached_data, /* possibly NULL */
406 : : int detached_data_len)
407 : 2 : {
408 : 2 : X509* x509 = NULL;
409 : 2 : PKCS7* p7 = NULL;
410 : 2 : STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
411 : 2 : X509_STORE* certs=NULL;
412 : 2 : BIO* detached = NULL;
413 : 2 : BIO* p7bio = NULL;
414 : 2 : BIO* wbio = NULL;
415 : 2 : char* data = NULL;
416 : : char buf[4096];
417 : : int i,x;
418 : :
419 [ + - - + ]: 2 : if (!sig_entity || !pubkey) GOTO_ERR("NULL arg(s)");
420 [ - + ]: 2 : if (!(p7 = get_pkcs7_from_pem(sig_entity))) goto err;
421 : :
422 : : /* Hmm, if its clear signed, we already provided the detached sig, but
423 : : * if its one sig blob, may be PKCS7_get_detached() provides BIO connected
424 : : * to the detached part. Go figure.
425 : : */
426 : :
427 [ # # # # ]: 0 : if (detached_data && detached_data_len) {
428 [ # # ]: 0 : if (!(detached = set_read_BIO_from_buf(detached_data, detached_data_len)))
429 : 0 : goto err;
430 : : } else {
431 [ # # ]: 0 : if (!PKCS7_get_detached(p7))
432 : 0 : GOTO_ERR("15 cant extract signed data from signed entity (PKCS7_get_detached)");
433 : : }
434 [ # # ]: 0 : if (!(p7bio=PKCS7_dataInit(p7,detached))) GOTO_ERR("PKCS7_dataInit");
435 : :
436 [ # # ]: 0 : if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
437 : :
438 : : /* We now have to 'read' from p7bio to calculate message digest(s).
439 : : * I also take the opportunity to save the signed data. */
440 : : for (;;) {
441 : 0 : i = BIO_read(p7bio,buf,sizeof(buf));
442 [ # # ]: 0 : if (i <= 0) break;
443 : 0 : BIO_write(wbio, buf, i);
444 : 0 : }
445 : :
446 [ # # ]: 0 : if (get_written_BIO_data(wbio, &data)==-1) goto err;
447 : 0 : BIO_free_all(wbio);
448 : 0 : wbio = NULL;
449 : :
450 : : /* We can now verify signatures */
451 [ # # ]: 0 : if (!(sigs=PKCS7_get_signer_info(p7)))
452 : 0 : GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
453 : :
454 : : /* Ok, first we need to, for each subject entry, see if we can verify */
455 [ # # ]: 0 : for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sigs); i++) {
456 : : PKCS7_SIGNER_INFO *si;
457 : :
458 : 0 : si=sk_PKCS7_SIGNER_INFO_value(sigs,i);
459 : :
460 : : /* The bio is needed here only to lookup the message digest context
461 : : * which presumably now contains the message digest. It will not be
462 : : * read, and hence its good for any number of iterations. This is so
463 : : * because MD bios pass the data right thru so they can be stacked
464 : : * to calculate multiple message digests simultaneously. Clever, eh?
465 : : */
466 : :
467 : : #if 0
468 : : /* *** this is currently broken and thus disabled. --Sampo */
469 : : /* verifies by looking up the certificate from certs database,
470 : : * verifying the validity of the certificate, and finally
471 : : * validity of the signature */
472 : :
473 : : X509_STORE_CTX cert_ctx;
474 : : x=PKCS7_dataVerify(certs, &cert_ctx, p7bio, p7, si);
475 : : #else
476 : : /* just verify the signature, given that we already have certificate
477 : : * candidate (see crypto/pk7_doit.c around line 675) */
478 : :
479 [ # # ]: 0 : if (!(x509 = extract_certificate(pubkey))) goto err;
480 : 0 : x=PKCS7_signatureVerify(p7bio, p7, si, x509);
481 : : #endif
482 [ # # ]: 0 : if (x <= 0) GOTO_ERR("14 sig verify failed");
483 : :
484 : : #if 0
485 : : ASN1_UTCTIME *tm;
486 : : if ((tm=get_signed_time(si)) != NULL) {
487 : : //fprintf(stderr,"Signed time:");
488 : : //ASN1_UTCTIME_print(bio_out,tm);
489 : : ASN1_UTCTIME_free(tm);
490 : : //BIO_printf(bio_out,"\n");
491 : : }
492 : : #endif
493 : : #if 0
494 : : char *str1,*str2;
495 : : if (get_signed_seq2string(si,&str1,&str2)) {
496 : : fprintf(stderr,"String 1 is %s\n",str1);
497 : : fprintf(stderr,"String 2 is %s\n",str2);
498 : : }
499 : : #endif
500 : : }
501 : :
502 : 0 : BIO_free_all(p7bio);
503 : 0 : PKCS7_free(p7);
504 : 0 : X509_STORE_free(certs);
505 : 0 : return data; /* return the signed plain text */
506 : :
507 : 2 : err:
508 [ - + ]: 2 : if (wbio) BIO_free_all(wbio);
509 [ - + ]: 2 : if (p7bio) BIO_free_all(p7bio);
510 [ - + ]: 2 : if (p7) PKCS7_free(p7);
511 [ - + ]: 2 : if (certs) X509_STORE_free(certs);
512 [ - + ]: 2 : if (data) OPENSSL_free(data);
513 : 2 : return NULL;
514 : : }
515 : :
516 : : /* =========== C E R T V E R I F I C A T I O N =========== */
517 : :
518 : : /* Called by: smime_verify_cert */
519 : : int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
520 : : verify_cert(X509* ca_cert, X509* cert)
521 : 0 : {
522 : 0 : EVP_PKEY* pkey = NULL;
523 [ # # # # ]: 0 : if (!ca_cert || !cert) GOTO_ERR("NULL arg(s)");
524 [ # # ]: 0 : if (!(pkey=X509_get_pubkey(ca_cert))) GOTO_ERR("no memory?");
525 : 0 : return X509_verify(cert, pkey);
526 : 0 : err:
527 : 0 : return -1;
528 : : }
529 : :
530 : : /* Called by: main */
531 : : int /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
532 : : smime_verify_cert(const char* ca_cert_pem, const char* cert_pem)
533 : 1 : {
534 : 1 : X509* ca_cert = NULL;
535 : 1 : X509* cert = NULL;
536 : 1 : int ret = -1;
537 [ + - - + ]: 1 : if (!ca_cert_pem || !cert_pem) GOTO_ERR("NULL arg(s)");
538 [ + - ]: 1 : if (!(ca_cert = extract_certificate(ca_cert_pem))) goto err;
539 [ - + ]: 1 : if (!(cert = extract_certificate(cert_pem))) goto err;
540 : 0 : ret = verify_cert(ca_cert, cert);
541 : 1 : err:
542 [ + - ]: 1 : if (ca_cert) X509_free(ca_cert);
543 [ - + ]: 1 : if (cert) X509_free(cert);
544 : 1 : return ret;
545 : : }
546 : :
547 : : /* EOF - smime-vfy.c */
|