00001
00002
00003
00004
00005
00006
00007
00008 #include <openssl/x509v3.h>
00009 #include <openssl/pem.h>
00010
00011 #include "wvcrl.h"
00012 #include "wvx509mgr.h"
00013 #include "wvbase64.h"
00014
00015
00016 static const char * warning_str_get = "Tried to determine %s, but CRL is blank!\n";
00017 #define CHECK_CRL_EXISTS_GET(x, y) \
00018 if (!crl) { \
00019 debug(WvLog::Warning, warning_str_get, x); \
00020 return y; \
00021 }
00022
00023
00024 static ASN1_INTEGER * serial_to_int(WvStringParm serial)
00025 {
00026 if (!!serial)
00027 {
00028 BIGNUM *bn = NULL;
00029 BN_dec2bn(&bn, serial);
00030 ASN1_INTEGER *retval = ASN1_INTEGER_new();
00031 retval = BN_to_ASN1_INTEGER(bn, retval);
00032 BN_free(bn);
00033 return retval;
00034 }
00035
00036 return NULL;
00037 }
00038
00039
00040 WvCRL::WvCRL()
00041 : debug("X509 CRL", WvLog::Debug5)
00042 {
00043 crl = NULL;
00044 }
00045
00046
00047 WvCRL::WvCRL(const WvX509Mgr &ca)
00048 : debug("X509 CRL", WvLog::Debug5)
00049 {
00050 assert(crl = X509_CRL_new());
00051
00052
00053
00054 X509_CRL_set_version(crl, 1);
00055 X509_CRL_set_issuer_name(crl, X509_get_issuer_name(ca.cert));
00056
00057
00058 ASN1_OCTET_STRING *ikeyid = NULL;
00059 X509_EXTENSION *ext;
00060 int i = X509_get_ext_by_NID(ca.cert, NID_subject_key_identifier, -1);
00061 if ((i >= 0) && (ext = X509_get_ext(ca.cert, i)))
00062 ikeyid = static_cast<ASN1_OCTET_STRING *>(X509V3_EXT_d2i(ext));
00063
00064 if (ikeyid)
00065 {
00066 AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
00067 akeyid->issuer = NULL;
00068 akeyid->serial = NULL;
00069 akeyid->keyid = ikeyid;
00070 ext = X509V3_EXT_i2d(NID_authority_key_identifier, 0, akeyid);
00071 X509_CRL_add_ext(crl, ext, -1);
00072 X509_EXTENSION_free(ext);
00073 AUTHORITY_KEYID_free(akeyid);
00074 }
00075
00076
00077 ca.signcrl(*this);
00078 }
00079
00080
00081 WvCRL::~WvCRL()
00082 {
00083 debug("Deleting.\n");
00084 if (crl)
00085 X509_CRL_free(crl);
00086 }
00087
00088
00089 bool WvCRL::isok() const
00090 {
00091 return crl;
00092 }
00093
00094
00095 bool WvCRL::signedbyca(const WvX509 &cacert) const
00096 {
00097 CHECK_CRL_EXISTS_GET("if CRL is signed by CA", false);
00098
00099 EVP_PKEY *pkey = X509_get_pubkey(cacert.cert);
00100 int result = X509_CRL_verify(crl, pkey);
00101 EVP_PKEY_free(pkey);
00102 if (result < 0)
00103 {
00104 debug("There was an error (%s) determining whether or not we were "
00105 "signed by CA '%s'\n", wvssl_errstr(), cacert.get_subject());
00106 return false;
00107 }
00108 bool issigned = (result > 0);
00109
00110 debug("CRL was%s signed by CA %s\n", issigned ? "" : " NOT",
00111 cacert.get_subject());
00112
00113 return issigned;
00114 }
00115
00116
00117 bool WvCRL::issuedbyca(const WvX509 &cacert) const
00118 {
00119 CHECK_CRL_EXISTS_GET("if CRL is issued by CA", false);
00120
00121 WvString name = get_issuer();
00122 bool issued = (cacert.get_subject() == name);
00123 if (issued)
00124 debug("CRL issuer '%s' matches subject '%s' of cert. We can say "
00125 "that it appears to be issued by this CA.\n",
00126 name, cacert.get_subject());
00127 else
00128 debug("CRL issuer '%s' doesn't match subject '%s' of cert. Doesn't "
00129 "appear to be issued by this CA.\n", name,
00130 cacert.get_subject());
00131
00132 return issued;
00133 }
00134
00135
00136 bool WvCRL::expired() const
00137 {
00138 CHECK_CRL_EXISTS_GET("if CRL has expired", false);
00139
00140 if (X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)) < 0)
00141 {
00142 debug("CRL appears to be expired.\n");
00143 return true;
00144 }
00145
00146 debug("CRL appears not to be expired.\n");
00147 return false;
00148 }
00149
00150
00151 bool WvCRL::has_critical_extensions() const
00152 {
00153 CHECK_CRL_EXISTS_GET("if CRL has critical extensions", false);
00154
00155 int critical = X509_CRL_get_ext_by_critical(crl, 1, 0);
00156 return (critical > 0);
00157 }
00158
00159
00160 WvString WvCRL::get_aki() const
00161 {
00162 CHECK_CRL_EXISTS_GET("CRL's AKI", WvString::null);
00163
00164 AUTHORITY_KEYID *aki = NULL;
00165 int i;
00166
00167 aki = static_cast<AUTHORITY_KEYID *>(
00168 X509_CRL_get_ext_d2i(crl, NID_authority_key_identifier,
00169 &i, NULL));
00170 if (aki)
00171 {
00172 char *tmp = hex_to_string(aki->keyid->data, aki->keyid->length);
00173 WvString str(tmp);
00174
00175 OPENSSL_free(tmp);
00176 AUTHORITY_KEYID_free(aki);
00177
00178 return str;
00179 }
00180
00181 return WvString::null;
00182 }
00183
00184
00185 WvString WvCRL::get_issuer() const
00186 {
00187 CHECK_CRL_EXISTS_GET("CRL's issuer", WvString::null);
00188
00189 char *name = X509_NAME_oneline(X509_CRL_get_issuer(crl), 0, 0);
00190 WvString retval(name);
00191 OPENSSL_free(name);
00192
00193 return retval;
00194 }
00195
00196
00197 WvString WvCRL::encode(const DumpMode mode) const
00198 {
00199 WvDynBuf retval;
00200 encode(mode, retval);
00201
00202 return retval.getstr();
00203 }
00204
00205
00206 void WvCRL::encode(const DumpMode mode, WvBuf &buf) const
00207 {
00208 if (mode == CRLFileDER || mode == CRLFilePEM)
00209 return;
00210
00211 if (!crl)
00212 {
00213 debug(WvLog::Warning, "Tried to encode CRL, but CRL is blank!\n");
00214 return;
00215 }
00216
00217 BIO *bufbio = BIO_new(BIO_s_mem());
00218 BUF_MEM *bm;
00219 switch (mode)
00220 {
00221 case CRLPEM:
00222 debug("Dumping CRL in PEM format.\n");
00223 PEM_write_bio_X509_CRL(bufbio, crl);
00224 break;
00225 case CRLDER:
00226 debug("Dumping CRL in DER format.\n");
00227 i2d_X509_CRL_bio(bufbio, crl);
00228 break;
00229 default:
00230 debug("Tried to dump CRL in unknown format!\n");
00231 break;
00232 }
00233
00234 BIO_get_mem_ptr(bufbio, &bm);
00235 buf.put(bm->data, bm->length);
00236 BIO_free(bufbio);
00237 }
00238
00239
00240 void WvCRL::decode(const DumpMode mode, WvStringParm str)
00241 {
00242 if (crl)
00243 {
00244 debug("Replacing already existant CRL.\n");
00245 X509_CRL_free(crl);
00246 crl = NULL;
00247 }
00248
00249 if (mode == CRLFileDER)
00250 {
00251 BIO *bio = BIO_new(BIO_s_file());
00252
00253 if (BIO_read_filename(bio, str.cstr()) <= 0)
00254 {
00255 debug(WvLog::Warning, "Import CRL from '%s': %s\n",
00256 str, wvssl_errstr());
00257 BIO_free(bio);
00258 return;
00259 }
00260
00261 if (!(crl = d2i_X509_CRL_bio(bio, NULL)))
00262 debug(WvLog::Warning, "Read CRL from '%s': %s\n",
00263 str, wvssl_errstr());
00264
00265 BIO_free(bio);
00266 return;
00267 }
00268 else if (mode == CRLFilePEM)
00269 {
00270 FILE * fp = fopen(str, "rb");
00271 if (!fp)
00272 {
00273 int errnum = errno;
00274 debug(WvLog::Warning,
00275 "open '%s': %s\n",
00276 str, strerror(errnum));
00277 return;
00278 }
00279
00280 if (!(crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL)))
00281 debug(WvLog::Warning, "Import CRL from '%s': %s\n",
00282 str, wvssl_errstr());
00283
00284 fclose(fp);
00285 return;
00286 }
00287
00288
00289 WvDynBuf buf;
00290 buf.putstr(str);
00291 decode(mode, buf);
00292 }
00293
00294
00295 void WvCRL::decode(const DumpMode mode, WvBuf &buf)
00296 {
00297 if (crl)
00298 {
00299 debug("Replacing already existant CRL.\n");
00300 X509_CRL_free(crl);
00301 crl = NULL;
00302 }
00303
00304 if (mode == CRLFileDER || mode == CRLFilePEM)
00305 {
00306 decode(mode, buf.getstr());
00307 return;
00308 }
00309
00310 BIO *bufbio = BIO_new(BIO_s_mem());
00311 BIO_write(bufbio, buf.get(buf.used()), buf.used());
00312
00313 if (mode == CRLPEM)
00314 {
00315 debug("Decoding CRL from PEM format.\n");
00316 crl = PEM_read_bio_X509_CRL(bufbio, NULL, NULL, NULL);
00317 }
00318 else if (mode == CRLDER)
00319 {
00320 debug("Decoding CRL from DER format.\n");
00321 crl = d2i_X509_CRL_bio(bufbio, NULL);
00322 }
00323 else
00324 debug(WvLog::Warning, "Attempted to decode unknown format.\n");
00325
00326 if (!crl)
00327 debug(WvLog::Warning, "Couldn't decode CRL.\n");
00328
00329 BIO_free(bufbio);
00330 }
00331
00332
00333 bool WvCRL::isrevoked(const WvX509 &cert) const
00334 {
00335 if (cert.cert)
00336 {
00337 debug("Checking to see if certificate with name '%s' and serial "
00338 "number '%s' is revoked.\n", cert.get_subject(),
00339 cert.get_serial());
00340 return isrevoked(cert.get_serial());
00341 }
00342 else
00343 {
00344 debug(WvLog::Error, "Given certificate to check revocation status, "
00345 "but certificate is blank. Declining.\n");
00346 return true;
00347 }
00348 }
00349
00350
00351 bool WvCRL::isrevoked(WvStringParm serial_number) const
00352 {
00353 CHECK_CRL_EXISTS_GET("if certificate is revoked in CRL", false);
00354
00355 if (!!serial_number)
00356 {
00357 ASN1_INTEGER *serial = serial_to_int(serial_number);
00358 if (serial)
00359 {
00360 X509_REVOKED mayberevoked;
00361 mayberevoked.serialNumber = serial;
00362 if (crl->crl->revoked)
00363 {
00364 int idx = sk_X509_REVOKED_find(crl->crl->revoked,
00365 &mayberevoked);
00366 ASN1_INTEGER_free(serial);
00367 if (idx >= 0)
00368 {
00369 debug("Certificate is revoked.\n");
00370 return true;
00371 }
00372 else
00373 {
00374 debug("Certificate is not revoked.\n");
00375 return false;
00376 }
00377 }
00378 else
00379 {
00380 ASN1_INTEGER_free(serial);
00381 debug("CRL does not have revoked list.\n");
00382 return false;
00383 }
00384
00385 }
00386 else
00387 debug(WvLog::Warning, "Can't convert serial number to ASN1 format. "
00388 "Saying it's not revoked.\n");
00389 }
00390 else
00391 debug(WvLog::Warning, "Serial number for certificate is blank.\n");
00392
00393 debug("Certificate is not revoked (or could not determine whether it "
00394 "was).\n");
00395 return false;
00396 }
00397
00398
00399 WvCRL::Valid WvCRL::validate(const WvX509 &cacert) const
00400 {
00401 if (!issuedbyca(cacert))
00402 return NOT_THIS_CA;
00403
00404 if (!signedbyca(cacert))
00405 return NO_VALID_SIGNATURE;
00406
00407 if (expired())
00408 return EXPIRED;
00409
00410
00411 if (has_critical_extensions())
00412 {
00413 debug("CRL has unhandled critical extensions.\n");
00414 return UNHANDLED_CRITICAL_EXTENSIONS;
00415 }
00416
00417 return VALID;
00418 }
00419
00420
00421 int WvCRL::numcerts() const
00422 {
00423 CHECK_CRL_EXISTS_GET("number of certificates in CRL", 0);
00424
00425 STACK_OF(X509_REVOKED) *rev;
00426 rev = X509_CRL_get_REVOKED(crl);
00427 int certcount = sk_X509_REVOKED_num(rev);
00428
00429 if (certcount < 0)
00430 certcount = 0;
00431
00432 return certcount;
00433 }
00434
00435
00436 void WvCRL::addcert(const WvX509 &cert)
00437 {
00438 if (!crl)
00439 {
00440 debug(WvLog::Warning, "Tried to add certificate to CRL, but CRL is "
00441 "blank!\n");
00442 return;
00443 }
00444
00445 if (cert.isok())
00446 {
00447 ASN1_INTEGER *serial = serial_to_int(cert.get_serial());
00448 X509_REVOKED *revoked = X509_REVOKED_new();
00449 ASN1_GENERALIZEDTIME *now = ASN1_GENERALIZEDTIME_new();
00450 X509_REVOKED_set_serialNumber(revoked, serial);
00451 X509_gmtime_adj(now, 0);
00452 X509_REVOKED_set_revocationDate(revoked, now);
00453
00454 X509_CRL_add0_revoked(crl, revoked);
00455 ASN1_GENERALIZEDTIME_free(now);
00456 ASN1_INTEGER_free(serial);
00457 }
00458 else
00459 {
00460 debug(WvLog::Warning, "Tried to add a certificate to the CRL, but "
00461 "certificate is either bad or broken.\n");
00462 }
00463 }
00464