7a159dc8f78d77c82c6dfa60bea7c678bb80cce8
[libksba.git] / src / cert.c
1 /* cert.c - main function for the certificate handling
2  *      Copyright (C) 2001 g10 Code GmbH
3  *
4  * This file is part of KSBA.
5  *
6  * KSBA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * KSBA is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "util.h"
28 #include "ber-decoder.h"
29 #include "convert.h"
30 #include "keyinfo.h"
31 #include "cert.h"
32
33
34 /**
35  * ksba_cert_new:
36  * 
37  * Create a new and empty certificate object
38  * 
39  * Return value: A cert object or NULL in case of memory problems.
40  **/
41 KsbaCert
42 ksba_cert_new (void)
43 {
44   KsbaCert cert;
45
46   cert = xtrycalloc (1, sizeof *cert);
47   if (!cert)
48     return NULL;
49
50
51   return cert;
52 }
53
54 /**
55  * ksba_cert_release:
56  * @cert: A certificate object
57  * 
58  * Release a certificate object.
59  **/
60 void
61 ksba_cert_release (KsbaCert cert)
62 {
63   /* FIXME: release cert->root, ->asn_tree */
64   xfree (cert);
65 }
66
67
68 /**
69  * ksba_cert_read_der:
70  * @cert: An unitialized certificate object
71  * @reader: A KSBA Reader object
72  * 
73  * Read the next certificate from the reader and store it in the
74  * certificate object for future access.  The certificate is parsed
75  * and rejected if it has any syntactical or semantical error
76  * (i.e. does not match the ASN.1 description).
77  * 
78  * Return value: 0 on success or an error value
79  **/
80 KsbaError
81 ksba_cert_read_der (KsbaCert cert, KsbaReader reader)
82 {
83   KsbaError err = 0;
84   BerDecoder decoder = NULL;
85
86   if (!cert || !reader)
87     return KSBA_Invalid_Value;
88   if (cert->initialized)
89     return KSBA_Conflict; /* FIXME: should remove the old one */
90
91   /* fixme: clear old cert->root */
92
93   /* fixme: Allow to configure the used syntax and read it from a static
94      structure generated by asn-gentables */
95   err = ksba_asn_parse_file ("../src/tmttv2.asn", &cert->asn_tree);
96   if (err)
97     goto leave;
98
99   decoder = _ksba_ber_decoder_new ();
100   if (!decoder)
101     {
102       err = KSBA_Out_Of_Core;
103       goto leave;
104     }
105
106   err = _ksba_ber_decoder_set_reader (decoder, reader);
107   if (err)
108     goto leave;
109   
110   err = _ksba_ber_decoder_set_module (decoder, cert->asn_tree);
111   if (err)
112      goto leave;
113
114   err = _ksba_ber_decoder_decode (decoder, &cert->root,
115                                   &cert->image, &cert->imagelen);
116   if (!err)
117       cert->initialized = 1;
118   
119  leave:
120   _ksba_ber_decoder_release (decoder);
121
122   return err;
123 }
124
125
126 KsbaError
127 ksba_cert_hash (KsbaCert cert,
128                 void (*hasher)(void *, const unsigned char *, size_t length), 
129                 void *hasher_arg)
130 {
131   AsnNode n;
132
133   if (!cert /*|| !hasher*/)
134     return KSBA_Invalid_Value;
135   if (!cert->initialized)
136     return KSBA_No_Data;
137
138   n = _ksba_asn_find_node (cert->root,
139                            "TMTTv2.Certificate.signatureAlgorithm");
140   if (!n)
141     return KSBA_No_Value; /* oops - should be there */
142   if (n->off == -1)
143     {
144       fputs ("ksba_cert_hash problem at node:\n", stderr);
145       _ksba_asn_node_dump_all (n, stderr);
146       return KSBA_No_Value;
147     }
148
149   {  
150     KsbaError err;
151     char *string;
152     AsnNode n2;
153 #if 0
154     err = _ksba_keyinfo_to_sexp (cert->image + n->off, n->nhdr + n->len,
155                                  &string);
156     if (err)
157       return err;
158     printf ("KEY = `%s'\n", string);
159 #endif
160     n2 = n->right;
161     
162     err = _ksba_sigval_to_sexp (cert->image + n->off,
163                                 n->nhdr + n->len
164                                 + ((!n2||n2->off == -1)? 0:(n2->nhdr+n2->len)),
165                                 &string);
166     if (err)
167       return err;
168     printf ("SIG = `%s'\n", string);
169   }
170
171   return 0;
172 }
173
174
175 /**
176  * ksba_cert_get_digest_algo:
177  * @cert: Initialized certificate object
178  * 
179  * Figure out the the digest algorithm used for the signature and
180  * return it as a number suitable to be used to identify a digest
181  * algorithm in Libgcrypt.
182  *
183  * This function is intended as a helper for the ksba_cert_hash().
184  * 
185  * Return value: 0 for error or unknown algoritm, otherwise a
186  * GCRY_MD_xxx constant.
187  **/
188 int
189 ksba_cert_get_digest_algo (KsbaCert cert)
190 {
191   AsnNode n;
192   int algo;
193
194   if (!cert)
195     return KSBA_Invalid_Value;
196   if (!cert->initialized)
197     return KSBA_No_Data;
198
199   n = _ksba_asn_find_node (cert->root,
200                            "TMTTv2.Certificate.signatureAlgorithm.algorithm");
201   algo = _ksba_map_oid_to_digest_algo (cert->image, n);
202   if (!algo)
203     cert->last_error = KSBA_Unknown_Algorithm;
204   else if (algo == -1)
205     {
206       cert->last_error = KSBA_No_Value;
207       algo = 0;
208     }
209
210   return algo;
211 }
212
213
214
215
216 /**
217  * ksba_cert_get_serial:
218  * @cert: certificate object 
219  * 
220  * This function returnes the serial number of the certificate.  The
221  * serial number is an integer returned in a buffer formatte in a
222  * format like the one ised bey SSH: The first 4 bytes are to be
223  * considered the length of the following integer bytes in network
224  * byte order, the integer itself is in 2's complement.  This format
225  * can be passed to gcry_mpi_scan() when a length of 0 is given.  The
226  * caller must free the buffer.
227  * 
228  * Return value: An allocated buffer or NULL for no value.
229  **/
230 unsigned char *
231 ksba_cert_get_serial (KsbaCert cert)
232 {
233   AsnNode n;
234   char *p;
235
236   if (!cert || !cert->initialized)
237     return NULL;
238   
239   n = _ksba_asn_find_node (cert->root,
240                            "TMTTv2.Certificate.tbsCertificate.serialNumber");
241   if (!n)
242     return NULL; /* oops - should be there */
243
244   if (n->off == -1)
245     {
246       fputs ("get_serial problem at node:\n", stderr);
247       _ksba_asn_node_dump_all (n, stderr);
248       return NULL;
249     }
250   
251   p = xtrymalloc ( n->len + 4 );
252   return_null_if_fail (p);
253
254   p[0] = n->len >> 24;
255   p[1] = n->len >> 16;
256   p[2] = n->len >> 8;
257   p[3] = n->len;
258   memcpy (p+4, cert->image + n->off + n->nhdr, n->len);
259   return p;
260 }
261
262 /**
263  * ksba_cert_get_issuer:
264  * @cert: certificate object
265  * 
266  * Returns the Distinguished Name (DN) of the certificate issuer which
267  * in most cases is a CA.  The format of the returned string is in
268  * accordance with RFC-2253.  NULL is returned if the DN is not
269  * available which is an error and should have been catched by the
270  * certificate reading function.
271  * 
272  * The caller must free the returned string using ksba_free() or the
273  * function he has registered as a replacement.
274  * 
275  * Return value: An allocated string or NULL for error.
276  **/
277 char *
278 ksba_cert_get_issuer (KsbaCert cert)
279 {
280   KsbaError err;
281   AsnNode n;
282   char *p;
283
284   if (!cert || !cert->initialized)
285     return NULL;
286   
287   n = _ksba_asn_find_node (cert->root,
288                            "TMTTv2.Certificate.tbsCertificate.issuer");
289   if (!n || !n->down)
290     return NULL; /* oops - should be there */
291   n = n->down; /* dereference the choice node */
292
293   if (n->off == -1)
294     {
295       fputs ("get_issuer problem at node:\n", stderr);
296       _ksba_asn_node_dump_all (n, stderr);
297       return NULL;
298     }
299   err = _ksba_dn_to_str (cert->image, n, &p);
300   if (err)
301     {
302       cert->last_error = err;
303       return NULL;
304     }
305   return p;
306 }
307
308
309
310 /**
311  * ksba_cert_get_valididy:
312  * @cert: cetificate object
313  * @what: 0 for notBefore, 1 for notAfter
314  * 
315  * Return the validity object from the certificate.  If no value is
316  * available 0 is returned becuase we can safely assume that this is
317  * not a valid date.
318  * 
319  * Return value: seconds since epoch, 0 for no value or (time)-1 for error.
320  **/
321 time_t
322 ksba_cert_get_validity (KsbaCert cert, int what)
323 {
324   AsnNode n, n2;
325   time_t t;
326
327   if (!cert || what < 0 || what > 1)
328     return (time_t)(-1);
329   if (!cert->initialized)
330     return (time_t)(-1);
331   
332   n = _ksba_asn_find_node (cert->root,
333         what == 0? "TMTTv2.Certificate.tbsCertificate.validity.notBefore"
334                  : "TMTTv2.Certificate.tbsCertificate.validity.notAfter");
335   if (!n)
336     return 0; /* no value available */
337
338   /* FIXME: We should remove the choice node and don't use this ugly hack */
339   for (n2=n->down; n2; n2 = n2->right)
340     {
341       if ((n2->type == TYPE_UTC_TIME || n2->type == TYPE_GENERALIZED_TIME)
342           && n2->off != -1)
343         break;
344     }
345   n = n2;
346   if (!n)
347     return 0; /* no value available */
348
349   return_val_if_fail (n->off != -1, (time_t)(-1));
350
351   t = _ksba_asntime_to_epoch (cert->image + n->off + n->nhdr, n->len);
352   if (!t) /* we consider this an error */
353     t = (time_t)(-1);
354   return t;
355 }
356
357
358 /* See ..get_issuer */
359 char *
360 ksba_cert_get_subject (KsbaCert cert)
361 {
362   KsbaError err;
363   AsnNode n;
364   char *p;
365
366   if (!cert || !cert->initialized)
367     return NULL;
368   
369   n = _ksba_asn_find_node (cert->root,
370                            "TMTTv2.Certificate.tbsCertificate.subject");
371   if (!n || !n->down)
372     return NULL; /* oops - should be there */
373   n = n->down; /* dereference the choice node */
374
375   if (n->off == -1)
376     {
377       fputs ("get_issuer problem at node:\n", stderr);
378       _ksba_asn_node_dump_all (n, stderr);
379       return NULL;
380     }
381   err = _ksba_dn_to_str (cert->image, n, &p);
382   if (err)
383     {
384       cert->last_error = err;
385       return NULL;
386     }
387   return p;
388 }
389
390
391 char *
392 ksba_cert_get_public_key (KsbaCert cert)
393 {
394   AsnNode n;
395   KsbaError err;
396   char *string;
397
398   if (!cert)
399     return NULL;
400   if (!cert->initialized)
401     return NULL;
402
403   n = _ksba_asn_find_node (cert->root,
404                            "TMTTv2.Certificate"
405                            ".tbsCertificate.subjectPublicKeyInfo");
406   if (!n)
407     {
408       cert->last_error = KSBA_No_Value;
409       return NULL;
410     }
411
412   err = _ksba_keyinfo_to_sexp (cert->image + n->off, n->nhdr + n->len,
413                                &string);
414   if (err)
415     {
416       cert->last_error = err;
417       return NULL;
418     }
419
420   return string;
421 }
422
423 char *
424 ksba_cert_get_sig_val (KsbaCert cert)
425 {
426   AsnNode n, n2;
427   KsbaError err;
428   char *string;
429
430   if (!cert)
431     return NULL;
432   if (!cert->initialized)
433     return NULL;
434
435   n = _ksba_asn_find_node (cert->root,
436                            "TMTTv2.Certificate.algorithmIdentifier");
437   if (!n)
438     {
439       cert->last_error = KSBA_No_Value;
440       return NULL;
441     }
442
443   n2 = n->right;
444   err = _ksba_sigval_to_sexp (cert->image + n->off,
445                               n->nhdr + n->len
446                               + ((!n2||n2->off == -1)? 0:(n2->nhdr+n2->len)),
447                               &string);
448   if (err)
449     {
450       cert->last_error = err;
451       return NULL;
452     }
453
454   return string;
455 }
456
457
458