2 #include "wvsslhacks.h"
4 #include "wvautoconf.h"
6 #include <openssl/pem.h>
7 #include <openssl/x509v3.h>
8 #include <openssl/err.h>
9 #include <openssl/ssl.h>
10 #include <openssl/sha.h>
11 #include <openssl/pkcs12.h>
17 AutoClose(FILE *fp
): fp(fp
) { }
24 operator FILE *() const
32 } // anomymous namespace...
35 WvX509Mgr::WvX509Mgr()
37 debug("X509 Manager", WvLog::Debug5
)
43 WvX509Mgr::WvX509Mgr(WvStringParm _dname
, WvRSAKey
*_rsa
, bool ca
)
45 debug("X509 Manager", WvLog::Debug5
)
47 debug("Creating new certificate+key pair for %s.\n", _dname
);
52 create_selfissued(_dname
, ca
);
53 debug("Ok - Parameters set... now signing certificate.\n");
57 debug("Sorry, can't create an anonymous certificate.");
61 WvX509Mgr::WvX509Mgr(WvStringParm _dname
, int bits
, bool ca
)
63 debug("X509 Manager", WvLog::Debug5
)
65 debug("Creating new certificate+key pair for %s.\n", _dname
);
70 rsa
= new WvRSAKey(bits
);
71 create_selfissued(_dname
, ca
);
72 debug("Ok - Parameters set... now signing certificate.\n");
76 debug("Sorry, can't create an anonymous certificate.");
80 void WvX509Mgr::create_selfissued(WvStringParm dname
, bool is_ca
)
84 debug("Replacing already existant certificate...\n");
89 // double check RSA key
91 debug("RSA Key is fine.\n");
95 if ((cert
= X509_new()) == NULL
)
98 // Completely broken in my mind - this sets the version
99 // string to '3' (I guess version starts at 0)
102 // RFC2459 says that this number must be unique for each certificate
103 // issued by a CA. It may be that some web browsers get confused if
104 // more than one cert with the same name has the same serial number, so
111 set_lifetime(60*60*24*3650);
121 debug("Setting Extensions with CA Parameters.\n");
122 debug("Setting Key Usage.\n");
123 set_key_usage("critical, keyCertSign, cRLSign");
124 debug("Setting Basic Constraints.\n");
125 set_extension(NID_basic_constraints
, "critical, CA:TRUE");
126 debug("Setting Netscape Certificate Type.\n");
127 set_extension(NID_netscape_cert_type
, "SSL CA, S/MIME CA, Object Signing CA");
128 // debug("Setting Constraints.\n");
129 // set_constraints("requireExplicitPolicy");
133 debug("Setting Key Usage with normal server parameters\n");
135 set_key_usage("critical, digitalSignature, keyEncipherment, keyAgreement");
136 set_extension(NID_basic_constraints
, "CA:FALSE");
137 set_ext_key_usage("TLS Web Server Authentication,"
138 "TLS Web Client Authentication");
141 // we do not actually sign the certificate here: that must be done by the
142 // user (WvX509Mgr most likely)
144 debug("Certificate for %s created\n", dname
);
148 WvX509Mgr::~WvX509Mgr()
150 debug("Deleting.\n");
156 bool WvX509Mgr::isok() const
158 return WvX509::isok() && rsa
&& rsa
->isok() && test();
162 WvString
WvX509Mgr::errstr() const
165 return WvX509::errstr();
168 return "No RSA key set.";
169 else if (!rsa
->isok())
170 return "RSA key not valid.";
172 return "RSA key and certificate do not match.";
174 return WvString::empty
;
178 bool WvX509Mgr::bind_ssl(SSL_CTX
*ctx
)
180 if (SSL_CTX_use_certificate(ctx
, get_cert()) <= 0)
184 debug("Certificate activated.\n");
186 if (SSL_CTX_use_RSAPrivateKey(ctx
, rsa
->rsa
) <= 0)
190 debug("RSA private key activated.\n");
195 bool WvX509Mgr::test() const
199 debug("No X509 certificate: test fails.\n");
205 EVP_PKEY
*pk
= EVP_PKEY_new();
208 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
210 debug("Error setting RSA keys: test fails.\n");
216 int verify_return
= X509_verify(cert
, pk
);
218 if (verify_return
!= 1) // only '1' means okay
220 // However let's double check:
221 WvString rsapub
= rsa
->encode(WvRSAKey::RsaPubPEM
);
222 WvRSAKey
*temprsa
= get_rsa_pub();
223 WvString certpub
= temprsa
->encode(WvRSAKey::RsaPubPEM
);
225 // debug("rsapub:\n%s\n", rsapub);
226 // debug("certpub:\n%s\n", certpub);
227 if (certpub
== rsapub
)
228 ; // do nothing, since OpenSSL is lying
231 // I guess that it really did fail.
232 debug("Certificate test failed: %s\n", wvssl_errstr());
245 WvString
WvX509Mgr::signreq(WvStringParm pkcs10req
) const
247 debug("Signing a certificate request with: %s\n", get_subject());
250 debug(WvLog::Warning
, "Asked to sign certificate request, but not ok! "
255 // Break this next part out into a de-pemify section, since that is what
256 // this part up until the FIXME: is about.
257 WvString
pkcs10(pkcs10req
);
259 char *begin
= strstr(pkcs10
.edit(), "\nMII");
262 debug("This doesn't look like PEM Encoded information...\n");
263 return WvString::null
;
265 char *end
= strstr(begin
+ 1, "\n---");
268 debug("Is this a complete certificate request?\n");
269 return WvString::null
;
272 WvString
body(begin
); // just the PKCS#10 request,
273 // without the ---BEGIN and ---END
277 dec
.flushstrbuf(body
, reqbuf
, true);
279 // FIXME: Duplicates code from cert_selfsign
280 size_t reqlen
= reqbuf
.used();
281 const unsigned char *req
= reqbuf
.get(reqlen
);
282 X509_REQ
*certreq
= wv_d2i_X509_REQ(NULL
, &req
, reqlen
);
285 WvX509
newcert(X509_new());
287 newcert
.set_subject(X509_REQ_get_subject_name(certreq
));
288 newcert
.set_version();
290 // Set the Serial Number for the certificate
293 newcert
.set_serial(serial
);
295 newcert
.set_lifetime(60*60*24*3650);
297 // The public key of the new cert should be the same as that from
299 EVP_PKEY
*pk
= X509_REQ_get_pubkey(certreq
);
300 X509_set_pubkey(newcert
.get_cert(), pk
);
303 // every good cert needs an ski+aki
305 newcert
.set_aki(*this);
307 // The Issuer name is the subject name of the current cert
308 newcert
.set_issuer(*this);
310 X509_EXTENSION
*ex
= NULL
;
311 // Set the RFC2459-mandated keyUsage field to critical, and restrict
312 // the usage of this cert to digital signature and key encipherment.
313 newcert
.set_key_usage("critical, digitalSignature, keyEncipherment");
315 // This could cause Netscape to barf because if we set basicConstraints
316 // to critical, we break RFC2459 compliance. Why they chose to enforce
317 // that bit, and not the rest is beyond me... but oh well...
318 ex
= X509V3_EXT_conf_nid(NULL
, NULL
, NID_basic_constraints
,
321 X509_add_ext(newcert
.get_cert(), ex
, -1);
322 X509_EXTENSION_free(ex
);
324 newcert
.set_ext_key_usage("critical, TLS Web Client Authentication");
328 X509_REQ_free(certreq
);
329 return WvString(newcert
.encode(WvX509::CertPEM
));
333 debug("Can't decode Certificate Request\n");
334 return WvString::null
;
339 bool WvX509Mgr::signcert(WvX509
&unsignedcert
) const
343 debug(WvLog::Warning
, "Asked to sign certificate, but not ok! "
348 if (cert
== unsignedcert
.cert
)
350 debug("Self Signing!\n");
352 #ifdef HAVE_OPENSSL_POLICY_MAPPING
353 else if (!X509_check_ca(cert
))
355 debug("This certificate is not a CA, and is thus not allowed to sign "
360 else if (!((cert
->ex_flags
& EXFLAG_KUSAGE
) &&
361 (cert
->ex_kusage
& KU_KEY_CERT_SIGN
)))
363 debug("This Certificate is not allowed to sign certificates!\n");
367 debug("Ok, now sign the new cert with the current RSA key.\n");
368 EVP_PKEY
*certkey
= EVP_PKEY_new();
369 bool cakeyok
= EVP_PKEY_set1_RSA(certkey
, rsa
->rsa
);
372 X509_sign(unsignedcert
.get_cert(), certkey
, EVP_sha1());
376 debug("No keys??\n");
377 EVP_PKEY_free(certkey
);
381 EVP_PKEY_free(certkey
);
386 bool WvX509Mgr::signcrl(WvCRL
&crl
) const
388 if (!isok() || !crl
.isok())
390 debug(WvLog::Warning
, "Asked to sign CRL, but certificate or CRL (or "
391 "both) not ok! Aborting.\n");
394 #ifdef HAVE_OPENSSL_POLICY_MAPPING
395 else if (!X509_check_ca(cert
))
397 debug("This certificate is not a CA, and is thus not allowed to sign "
402 else if (!((cert
->ex_flags
& EXFLAG_KUSAGE
) &&
403 (cert
->ex_kusage
& KU_CRL_SIGN
)))
405 debug("Certificate not allowed to sign CRLs! (%s %s)\n",
406 (cert
->ex_flags
& EXFLAG_KUSAGE
), (cert
->ex_kusage
& KU_CRL_SIGN
));
410 EVP_PKEY
*certkey
= EVP_PKEY_new();
411 bool cakeyok
= EVP_PKEY_set1_RSA(certkey
, rsa
->rsa
);
414 // Use Version 2 CRLs - Of COURSE that means
415 // to set it to 1 here... grumble..
416 X509_CRL_set_version(crl
.getcrl(), 1);
418 X509_CRL_set_issuer_name(crl
.getcrl(), X509_get_subject_name(cert
));
420 ASN1_TIME
*tmptm
= ASN1_TIME_new();
421 // Set the LastUpdate time to now.
422 X509_gmtime_adj(tmptm
, 0);
423 X509_CRL_set_lastUpdate(crl
.getcrl(), tmptm
);
424 // CRL's are valid for 30 days
425 X509_gmtime_adj(tmptm
, (long)60*60*24*30);
426 X509_CRL_set_nextUpdate(crl
.getcrl(), tmptm
);
427 ASN1_TIME_free(tmptm
);
429 // OK - now sign it...
430 X509_CRL_sign(crl
.getcrl(), certkey
, EVP_sha1());
434 debug(WvLog::Warning
, "Asked to sign CRL, but no RSA key associated "
435 "with certificate. Aborting.\n");
436 EVP_PKEY_free(certkey
);
439 EVP_PKEY_free(certkey
);
445 WvString
WvX509Mgr::sign(WvStringParm data
) const
453 WvString
WvX509Mgr::sign(WvBuf
&data
) const
458 unsigned char sig_buf
[4096];
460 EVP_PKEY
*pk
= EVP_PKEY_new();
463 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
465 debug("Error setting RSA keys.\n");
467 return WvString::null
;
470 EVP_SignInit(&sig_ctx
, EVP_sha1());
471 EVP_SignUpdate(&sig_ctx
, data
.peek(0, data
.used()), data
.used());
472 unsigned int sig_len
= sizeof(sig_buf
);
473 int sig_err
= EVP_SignFinal(&sig_ctx
, sig_buf
,
477 debug("Error while signing.\n");
479 return WvString::null
;
483 EVP_MD_CTX_cleanup(&sig_ctx
); // this isn't my fault ://
485 buf
.put(sig_buf
, sig_len
);
486 debug("Signature size: %s\n", buf
.used());
487 return WvBase64Encoder().strflushbuf(buf
, true);
491 bool WvX509Mgr::write_p12(WvStringParm _fname
, WvStringParm _pkcs12pass
) const
493 debug("Dumping RSA Key and X509 Cert to PKCS12 structure.\n");
495 AutoClose fp
= fopen(_fname
, "wb");
499 debug(WvLog::Warning
, "Unable to open file. Error: %s\n", strerror(errno
));
507 EVP_PKEY
*pk
= EVP_PKEY_new();
510 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
512 debug("Error setting RSA keys.\n");
518 WvString
pkcs12pass(_pkcs12pass
);
519 PKCS12
*pkg
= PKCS12_create(pkcs12pass
.edit(), (char*)"foo", pk
,
524 debug("Writing the PKCS12 object out...\n");
525 i2d_PKCS12_fp(fp
, pkg
);
531 debug(WvLog::Warning
, "Unable to create PKCS12 object.");
539 debug(WvLog::Warning
, "The RSA key or the certificate is not present.");
545 debug(WvLog::Warning
, "No password specified for PKCS12 dump.");
553 void WvX509Mgr::read_p12(WvStringParm _fname
, WvStringParm _pkcs12pass
)
555 debug("Reading Certificate and Private Key from PKCS12 file: %s\n", _fname
);
560 AutoClose fp
= fopen(_fname
, "r");
564 debug("Unable to open file '%s'!\n", _fname
);
570 PKCS12
*pkg
= d2i_PKCS12_fp(fp
, NULL
);
575 // Parse out the bits out the PKCS12 package.
577 PKCS12_parse(pkg
, _pkcs12pass
, &pk
, &x
, NULL
);
581 debug("Could not decode pkcs12 file.\n");
588 // Now, cert should be OK, let's try and set up the RSA stuff
589 // since we've essentially got a PKEY, and not a WvRSAKey
590 // We need to create a new WvRSAKey from the PKEY...
591 rsa
= new WvRSAKey(EVP_PKEY_get1_RSA(pk
), true);
594 // Now that we have both, check to make sure that they match
597 debug("Could not fill in RSA and certificate with matching "
598 "values! Expect problems.\n");
604 debug("Read in of PKCS12 file '%s' failed", _fname
);
610 debug("No password specified for PKCS12 file\n");
616 WvString
WvX509Mgr::encode(const WvRSAKey::DumpMode mode
) const
619 return rsa
->encode(mode
);
624 WvString
WvX509Mgr::encode(const WvX509::DumpMode mode
) const
626 return WvX509::encode(mode
);
630 void WvX509Mgr::encode(const WvRSAKey::DumpMode mode
, WvBuf
&buf
) const
633 rsa
->encode(mode
, buf
);
637 void WvX509Mgr::encode(const WvX509::DumpMode mode
, WvBuf
&buf
) const
639 WvX509::encode(mode
, buf
);
643 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode
, WvStringParm encoded
)
646 rsa
->decode(mode
, encoded
);
649 rsa
= new WvRSAKey();
650 rsa
->decode(mode
, encoded
);
655 void WvX509Mgr::decode(const WvX509::DumpMode mode
, WvStringParm encoded
)
657 WvX509::decode(mode
, encoded
);
661 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode
, WvBuf
&encoded
)
664 rsa
->decode(mode
, encoded
);
667 rsa
= new WvRSAKey();
668 rsa
->decode(mode
, encoded
);
673 void WvX509Mgr::decode(const WvX509::DumpMode mode
, WvBuf
&encoded
)
675 WvX509::decode(mode
, encoded
);