2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2005 Net Integration Technologies, Inc.
5 * X.509v3 CRL management classes.
8 #include <openssl/x509v3.h>
9 #include <openssl/pem.h>
12 #include "wvx509mgr.h"
15 static const char * warning_str_get
= "Tried to determine %s, but CRL is blank!\n";
16 #define CHECK_CRL_EXISTS_GET(x, y) \
18 debug(WvLog::Warning, warning_str_get, x); \
22 static ASN1_INTEGER
* serial_to_int(WvStringParm serial
)
27 BN_dec2bn(&bn
, serial
);
28 ASN1_INTEGER
*retval
= ASN1_INTEGER_new();
29 retval
= BN_to_ASN1_INTEGER(bn
, retval
);
39 : debug("X509 CRL", WvLog::Debug5
)
45 WvCRL::WvCRL(const WvX509Mgr
&cacert
)
46 : debug("X509 CRL", WvLog::Debug5
)
48 assert(crl
= X509_CRL_new());
49 cacert
.signcrl(*this);
61 bool WvCRL::isok() const
67 bool WvCRL::signedbyca(const WvX509
&cacert
) const
69 CHECK_CRL_EXISTS_GET("if CRL is signed by CA", false);
71 EVP_PKEY
*pkey
= X509_get_pubkey(cacert
.cert
);
72 int result
= X509_CRL_verify(crl
, pkey
);
76 debug("There was an error determining whether or not we were signed by "
77 "CA '%s'\n", cacert
.get_subject());
80 bool issigned
= (result
> 0);
82 debug("CRL was%s signed by CA %s\n", issigned
? "" : " NOT",
83 cacert
.get_subject());
89 bool WvCRL::issuedbyca(const WvX509
&cacert
) const
91 CHECK_CRL_EXISTS_GET("if CRL is issued by CA", false);
93 WvString name
= get_issuer();
94 bool issued
= (cacert
.get_subject() == name
);
96 debug("CRL issuer '%s' matches subject '%s' of cert. We can say "
97 "that it appears to be issued by this CA.\n",
98 name
, cacert
.get_subject());
100 debug("CRL issuer '%s' doesn't match subject '%s' of cert. Doesn't "
101 "appear to be issued by this CA.\n", name
,
102 cacert
.get_subject());
108 bool WvCRL::expired() const
110 CHECK_CRL_EXISTS_GET("if CRL has expired", false);
112 if (X509_cmp_current_time(X509_CRL_get_nextUpdate(crl
)) < 0)
114 debug("CRL appears to be expired.\n");
118 debug("CRL appears not to be expired.\n");
123 bool WvCRL::has_critical_extensions() const
125 CHECK_CRL_EXISTS_GET("if CRL has critical extensions", false);
127 int critical
= X509_CRL_get_ext_by_critical(crl
, 1, 0);
128 return (critical
> 0);
132 WvString
WvCRL::get_aki() const
134 CHECK_CRL_EXISTS_GET("CRL's AKI", WvString::null
);
136 AUTHORITY_KEYID
*aki
= NULL
;
139 aki
= static_cast<AUTHORITY_KEYID
*>(
140 X509_CRL_get_ext_d2i(crl
, NID_authority_key_identifier
,
144 char *tmp
= hex_to_string(aki
->keyid
->data
, aki
->keyid
->length
);
148 AUTHORITY_KEYID_free(aki
);
153 return WvString::null
;
157 WvString
WvCRL::get_issuer() const
159 CHECK_CRL_EXISTS_GET("CRL's issuer", WvString::null
);
161 char *name
= X509_NAME_oneline(X509_CRL_get_issuer(crl
), 0, 0);
162 WvString
retval(name
);
169 WvString
WvCRL::encode(const DumpMode mode
) const
172 encode(mode
, retval
);
174 return retval
.getstr();
178 void WvCRL::encode(const DumpMode mode
, WvBuf
&buf
) const
180 if (mode
== CRLFileDER
|| mode
== CRLFilePEM
)
181 return; // file modes are no ops with encode
185 debug(WvLog::Warning
, "Tried to encode CRL, but CRL is blank!\n");
189 BIO
*bufbio
= BIO_new(BIO_s_mem());
194 debug("Dumping CRL in PEM format.\n");
195 PEM_write_bio_X509_CRL(bufbio
, crl
);
198 debug("Dumping CRL in DER format.\n");
199 i2d_X509_CRL_bio(bufbio
, crl
);
202 debug("Tried to dump CRL in unknown format!\n");
206 BIO_get_mem_ptr(bufbio
, &bm
);
207 buf
.put(bm
->data
, bm
->length
);
212 void WvCRL::decode(const DumpMode mode
, WvStringParm str
)
216 debug("Replacing already existant CRL.\n");
221 if (mode
== CRLFileDER
)
223 BIO
*bio
= BIO_new(BIO_s_file());
225 if (BIO_read_filename(bio
, str
.cstr()) <= 0)
227 debug(WvLog::Warning
, "Import CRL from '%s': %s\n",
228 str
, wvssl_errstr());
233 if (!(crl
= d2i_X509_CRL_bio(bio
, NULL
)))
234 debug(WvLog::Warning
, "Read CRL from '%s': %s\n",
235 str
, wvssl_errstr());
240 else if (mode
== CRLFilePEM
)
242 FILE * fp
= fopen(str
, "rb");
246 debug(WvLog::Warning
,
247 "Import CRL from '%s': %s\n",
248 str
, strerror(errnum
));
252 if (!(crl
= PEM_read_X509_CRL(fp
, NULL
, NULL
, NULL
)))
253 debug(WvLog::Warning
, "Can't read CRL from file");
259 // we use the buffer decode functions for everything else
266 void WvCRL::decode(const DumpMode mode
, WvBuf
&buf
)
270 debug("Replacing already existant CRL.\n");
275 if (mode
== CRLFileDER
|| mode
== CRLFilePEM
)
277 decode(mode
, buf
.getstr());
281 BIO
*bufbio
= BIO_new(BIO_s_mem());
282 BIO_write(bufbio
, buf
.get(buf
.used()), buf
.used());
286 debug("Decoding CRL from PEM format.\n");
287 crl
= PEM_read_bio_X509_CRL(bufbio
, NULL
, NULL
, NULL
);
289 else if (mode
== CRLDER
)
291 debug("Decoding CRL from DER format.\n");
292 crl
= d2i_X509_CRL_bio(bufbio
, NULL
);
295 debug(WvLog::Warning
, "Attempted to decode unknown format.\n");
298 debug(WvLog::Warning
, "Couldn't decode CRL.\n");
304 bool WvCRL::isrevoked(const WvX509
&cert
) const
308 debug("Checking to see if certificate with name '%s' and serial "
309 "number '%s' is revoked.\n", cert
.get_subject(),
311 return isrevoked(cert
.get_serial());
315 debug(WvLog::Error
, "Given certificate to check revocation status, "
316 "but certificate is blank. Declining.\n");
322 bool WvCRL::isrevoked(WvStringParm serial_number
) const
324 CHECK_CRL_EXISTS_GET("if certificate is revoked in CRL", false);
328 ASN1_INTEGER
*serial
= serial_to_int(serial_number
);
331 X509_REVOKED mayberevoked
;
332 mayberevoked
.serialNumber
= serial
;
333 if (crl
->crl
->revoked
)
335 int idx
= sk_X509_REVOKED_find(crl
->crl
->revoked
,
337 ASN1_INTEGER_free(serial
);
340 debug("Certificate is revoked.\n");
345 debug("Certificate is not revoked.\n");
351 ASN1_INTEGER_free(serial
);
352 debug("CRL does not have revoked list.\n");
358 debug(WvLog::Warning
, "Can't convert serial number to ASN1 format. "
359 "Saying it's not revoked.\n");
362 debug(WvLog::Warning
, "Serial number for certificate is blank.\n");
364 debug("Certificate is not revoked (or could not determine whether it "
370 WvCRL::Valid
WvCRL::validate(const WvX509
&cacert
) const
372 if (!issuedbyca(cacert
))
375 if (!signedbyca(cacert
))
376 return NO_VALID_SIGNATURE
;
381 // neither we or openssl handles any critical extensions yet
382 if (has_critical_extensions())
384 debug("CRL has unhandled critical extensions.\n");
385 return UNHANDLED_CRITICAL_EXTENSIONS
;
392 int WvCRL::numcerts() const
394 CHECK_CRL_EXISTS_GET("number of certificates in CRL", 0);
396 STACK_OF(X509_REVOKED
) *rev
;
397 rev
= X509_CRL_get_REVOKED(crl
);
398 int certcount
= sk_X509_REVOKED_num(rev
);
407 void WvCRL::addcert(const WvX509
&cert
)
411 debug(WvLog::Warning
, "Tried to add certificate to CRL, but CRL is "
418 ASN1_INTEGER
*serial
= serial_to_int(cert
.get_serial());
419 X509_REVOKED
*revoked
= X509_REVOKED_new();
420 ASN1_GENERALIZEDTIME
*now
= ASN1_GENERALIZEDTIME_new();
421 X509_REVOKED_set_serialNumber(revoked
, serial
);
422 X509_gmtime_adj(now
, 0);
423 X509_REVOKED_set_revocationDate(revoked
, now
);
424 // FIXME: We don't deal with the reason here...
425 X509_CRL_add0_revoked(crl
, revoked
);
426 ASN1_GENERALIZEDTIME_free(now
);
427 ASN1_INTEGER_free(serial
);
431 debug(WvLog::Warning
, "Tried to add a certificate to the CRL, but "
432 "certificate is either bad or broken.\n");