2 #include "wvsslhacks.h"
5 #include <openssl/pem.h>
6 #include <openssl/x509v3.h>
7 #include <openssl/err.h>
8 #include <openssl/ssl.h>
9 #include <openssl/sha.h>
10 #include <openssl/pkcs12.h>
16 AutoClose(FILE *fp
): fp(fp
) { }
23 operator FILE *() const
31 } // anomymous namespace...
34 WvX509Mgr::WvX509Mgr()
36 debug("X509 Manager", WvLog::Debug5
)
42 WvX509Mgr::WvX509Mgr(WvStringParm _dname
, WvRSAKey
*_rsa
, bool ca
)
44 debug("X509 Manager", WvLog::Debug5
)
46 debug("Creating new certificate+key pair for %s.\n", _dname
);
51 create_selfissued(_dname
, ca
);
52 debug("Ok - Parameters set... now signing certificate.\n");
56 debug("Sorry, can't create an anonymous certificate.");
60 WvX509Mgr::WvX509Mgr(WvStringParm _dname
, int bits
, bool ca
)
62 debug("X509 Manager", WvLog::Debug5
)
64 debug("Creating new certificate+key pair for %s.\n", _dname
);
69 rsa
= new WvRSAKey(bits
);
70 create_selfissued(_dname
, ca
);
71 debug("Ok - Parameters set... now signing certificate.\n");
75 debug("Sorry, can't create an anonymous certificate.");
79 void WvX509Mgr::create_selfissued(WvStringParm dname
, bool is_ca
)
83 debug("Replacing already existant certificate...\n");
88 // double check RSA key
90 debug("RSA Key is fine.\n");
94 if ((cert
= X509_new()) == NULL
)
97 // Completely broken in my mind - this sets the version
98 // string to '3' (I guess version starts at 0)
101 // RFC2459 says that this number must be unique for each certificate
102 // issued by a CA. It may be that some web browsers get confused if
103 // more than one cert with the same name has the same serial number, so
110 set_lifetime(60*60*24*3650);
120 debug("Setting Extensions with CA Parameters.\n");
121 debug("Setting Key Usage.\n");
122 set_key_usage("critical, keyCertSign, cRLSign");
123 debug("Setting Basic Constraints.\n");
124 set_extension(NID_basic_constraints
, "critical, CA:TRUE");
125 debug("Setting Netscape Certificate Type.\n");
126 set_extension(NID_netscape_cert_type
, "SSL CA, S/MIME CA, Object Signing CA");
127 // debug("Setting Constraints.\n");
128 // set_constraints("requireExplicitPolicy");
132 debug("Setting Key Usage with normal server parameters\n");
134 set_key_usage("critical, digitalSignature, keyEncipherment, keyAgreement");
135 set_extension(NID_basic_constraints
, "CA:FALSE");
136 set_ext_key_usage("TLS Web Server Authentication,"
137 "TLS Web Client Authentication");
140 // we do not actually sign the certificate here: that must be done by the
141 // user (WvX509Mgr most likely)
143 debug("Certificate for %s created\n", dname
);
147 WvX509Mgr::~WvX509Mgr()
149 debug("Deleting.\n");
155 bool WvX509Mgr::isok() const
157 return WvX509::isok() && rsa
&& rsa
->isok() && test();
161 WvString
WvX509Mgr::errstr() const
164 return WvX509::errstr();
167 return "No RSA key set.";
168 else if (!rsa
->isok())
169 return "RSA key not valid.";
171 return "RSA key and certificate do not match.";
173 return WvString::empty
;
177 bool WvX509Mgr::bind_ssl(SSL_CTX
*ctx
)
179 if (SSL_CTX_use_certificate(ctx
, get_cert()) <= 0)
183 debug("Certificate activated.\n");
185 if (SSL_CTX_use_RSAPrivateKey(ctx
, rsa
->rsa
) <= 0)
189 debug("RSA private key activated.\n");
194 bool WvX509Mgr::test() const
198 debug("No X509 certificate: test fails.\n");
204 EVP_PKEY
*pk
= EVP_PKEY_new();
207 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
209 debug("Error setting RSA keys: test fails.\n");
215 int verify_return
= X509_verify(cert
, pk
);
217 if (verify_return
!= 1) // only '1' means okay
219 // However let's double check:
220 WvString rsapub
= rsa
->encode(WvRSAKey::RsaPubPEM
);
221 WvRSAKey
*temprsa
= get_rsa_pub();
222 WvString certpub
= temprsa
->encode(WvRSAKey::RsaPubPEM
);
224 // debug("rsapub:\n%s\n", rsapub);
225 // debug("certpub:\n%s\n", certpub);
226 if (certpub
== rsapub
)
227 ; // do nothing, since OpenSSL is lying
230 // I guess that it really did fail.
231 debug("Certificate test failed: %s\n", wvssl_errstr());
244 WvString
WvX509Mgr::signreq(WvStringParm pkcs10req
) const
246 debug("Signing a certificate request with: %s\n", get_subject());
249 debug(WvLog::Warning
, "Asked to sign certificate request, but not ok! "
254 // Break this next part out into a de-pemify section, since that is what
255 // this part up until the FIXME: is about.
256 WvString
pkcs10(pkcs10req
);
258 char *begin
= strstr(pkcs10
.edit(), "\nMII");
261 debug("This doesn't look like PEM Encoded information...\n");
262 return WvString::null
;
264 char *end
= strstr(begin
+ 1, "\n---");
267 debug("Is this a complete certificate request?\n");
268 return WvString::null
;
271 WvString
body(begin
); // just the PKCS#10 request,
272 // without the ---BEGIN and ---END
276 dec
.flushstrbuf(body
, reqbuf
, true);
278 // FIXME: Duplicates code from cert_selfsign
279 size_t reqlen
= reqbuf
.used();
280 const unsigned char *req
= reqbuf
.get(reqlen
);
281 X509_REQ
*certreq
= wv_d2i_X509_REQ(NULL
, &req
, reqlen
);
284 WvX509
newcert(X509_new());
286 newcert
.set_subject(X509_REQ_get_subject_name(certreq
));
287 newcert
.set_version();
289 // Set the Serial Number for the certificate
292 newcert
.set_serial(serial
);
294 newcert
.set_lifetime(60*60*24*3650);
296 // The public key of the new cert should be the same as that from
298 EVP_PKEY
*pk
= X509_REQ_get_pubkey(certreq
);
299 X509_set_pubkey(newcert
.get_cert(), pk
);
302 // every good cert needs an ski+aki
304 newcert
.set_aki(*this);
306 // The Issuer name is the subject name of the current cert
307 newcert
.set_issuer(*this);
309 X509_EXTENSION
*ex
= NULL
;
310 // Set the RFC2459-mandated keyUsage field to critical, and restrict
311 // the usage of this cert to digital signature and key encipherment.
312 newcert
.set_key_usage("critical, digitalSignature, keyEncipherment");
314 // This could cause Netscape to barf because if we set basicConstraints
315 // to critical, we break RFC2459 compliance. Why they chose to enforce
316 // that bit, and not the rest is beyond me... but oh well...
317 ex
= X509V3_EXT_conf_nid(NULL
, NULL
, NID_basic_constraints
,
320 X509_add_ext(newcert
.get_cert(), ex
, -1);
321 X509_EXTENSION_free(ex
);
323 newcert
.set_ext_key_usage("critical, TLS Web Client Authentication");
327 X509_REQ_free(certreq
);
328 return WvString(newcert
.encode(WvX509::CertPEM
));
332 debug("Can't decode Certificate Request\n");
333 return WvString::null
;
338 bool WvX509Mgr::signcert(WvX509
&unsignedcert
) const
342 debug(WvLog::Warning
, "Asked to sign certificate, but not ok! "
347 if (cert
== unsignedcert
.cert
)
349 debug("Self Signing!\n");
351 else if (!X509_check_ca(cert
))
353 debug("This certificate is not a CA, and is thus not allowed to sign "
357 else if (!((cert
->ex_flags
& EXFLAG_KUSAGE
) &&
358 (cert
->ex_kusage
& KU_KEY_CERT_SIGN
)))
360 debug("This Certificate is not allowed to sign certificates!\n");
364 debug("Ok, now sign the new cert with the current RSA key.\n");
365 EVP_PKEY
*certkey
= EVP_PKEY_new();
366 bool cakeyok
= EVP_PKEY_set1_RSA(certkey
, rsa
->rsa
);
369 X509_sign(unsignedcert
.get_cert(), certkey
, EVP_sha1());
373 debug("No keys??\n");
374 EVP_PKEY_free(certkey
);
378 EVP_PKEY_free(certkey
);
383 bool WvX509Mgr::signcrl(WvCRL
&crl
) const
385 if (!isok() || !crl
.isok())
387 debug(WvLog::Warning
, "Asked to sign CRL, but certificate or CRL (or "
388 "both) not ok! Aborting.\n");
391 else if (!X509_check_ca(cert
))
393 debug("This certificate is not a CA, and is thus not allowed to sign "
397 else if (!((cert
->ex_flags
& EXFLAG_KUSAGE
) &&
398 (cert
->ex_kusage
& KU_CRL_SIGN
)))
400 debug("Certificate not allowed to sign CRLs! (%s %s)\n",
401 (cert
->ex_flags
& EXFLAG_KUSAGE
), (cert
->ex_kusage
& KU_CRL_SIGN
));
405 EVP_PKEY
*certkey
= EVP_PKEY_new();
406 bool cakeyok
= EVP_PKEY_set1_RSA(certkey
, rsa
->rsa
);
409 // Use Version 2 CRLs - Of COURSE that means
410 // to set it to 1 here... grumble..
411 X509_CRL_set_version(crl
.getcrl(), 1);
413 X509_CRL_set_issuer_name(crl
.getcrl(), X509_get_subject_name(cert
));
415 ASN1_TIME
*tmptm
= ASN1_TIME_new();
416 // Set the LastUpdate time to now.
417 X509_gmtime_adj(tmptm
, 0);
418 X509_CRL_set_lastUpdate(crl
.getcrl(), tmptm
);
419 // CRL's are valid for 30 days
420 X509_gmtime_adj(tmptm
, (long)60*60*24*30);
421 X509_CRL_set_nextUpdate(crl
.getcrl(), tmptm
);
422 ASN1_TIME_free(tmptm
);
424 // OK - now sign it...
425 X509_CRL_sign(crl
.getcrl(), certkey
, EVP_sha1());
429 debug(WvLog::Warning
, "Asked to sign CRL, but no RSA key associated "
430 "with certificate. Aborting.\n");
431 EVP_PKEY_free(certkey
);
434 EVP_PKEY_free(certkey
);
440 WvString
WvX509Mgr::sign(WvStringParm data
) const
448 WvString
WvX509Mgr::sign(WvBuf
&data
) const
453 unsigned char sig_buf
[4096];
455 EVP_PKEY
*pk
= EVP_PKEY_new();
458 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
460 debug("Error setting RSA keys.\n");
462 return WvString::null
;
465 EVP_SignInit(&sig_ctx
, EVP_sha1());
466 EVP_SignUpdate(&sig_ctx
, data
.peek(0, data
.used()), data
.used());
467 unsigned int sig_len
= sizeof(sig_buf
);
468 int sig_err
= EVP_SignFinal(&sig_ctx
, sig_buf
,
472 debug("Error while signing.\n");
474 return WvString::null
;
478 EVP_MD_CTX_cleanup(&sig_ctx
); // this isn't my fault ://
480 buf
.put(sig_buf
, sig_len
);
481 debug("Signature size: %s\n", buf
.used());
482 return WvBase64Encoder().strflushbuf(buf
, true);
486 bool WvX509Mgr::write_p12(WvStringParm _fname
, WvStringParm _pkcs12pass
) const
488 debug("Dumping RSA Key and X509 Cert to PKCS12 structure.\n");
490 AutoClose fp
= fopen(_fname
, "wb");
494 debug(WvLog::Warning
, "Unable to open file. Error: %s\n", strerror(errno
));
502 EVP_PKEY
*pk
= EVP_PKEY_new();
505 if (!EVP_PKEY_set1_RSA(pk
, rsa
->rsa
))
507 debug("Error setting RSA keys.\n");
513 WvString
pkcs12pass(_pkcs12pass
);
514 PKCS12
*pkg
= PKCS12_create(pkcs12pass
.edit(), (char*)"foo", pk
,
519 debug("Writing the PKCS12 object out...\n");
520 i2d_PKCS12_fp(fp
, pkg
);
526 debug(WvLog::Warning
, "Unable to create PKCS12 object.");
534 debug(WvLog::Warning
, "The RSA key or the certificate is not present.");
540 debug(WvLog::Warning
, "No password specified for PKCS12 dump.");
548 void WvX509Mgr::read_p12(WvStringParm _fname
, WvStringParm _pkcs12pass
)
550 debug("Reading Certificate and Private Key from PKCS12 file: %s\n", _fname
);
555 AutoClose fp
= fopen(_fname
, "r");
559 debug("Unable to open file '%s'!\n", _fname
);
565 PKCS12
*pkg
= d2i_PKCS12_fp(fp
, NULL
);
570 // Parse out the bits out the PKCS12 package.
572 PKCS12_parse(pkg
, _pkcs12pass
, &pk
, &x
, NULL
);
576 debug("Could not decode pkcs12 file.\n");
583 // Now, cert should be OK, let's try and set up the RSA stuff
584 // since we've essentially got a PKEY, and not a WvRSAKey
585 // We need to create a new WvRSAKey from the PKEY...
586 rsa
= new WvRSAKey(EVP_PKEY_get1_RSA(pk
), true);
589 // Now that we have both, check to make sure that they match
592 debug("Could not fill in RSA and certificate with matching "
593 "values! Expect problems.\n");
599 debug("Read in of PKCS12 file '%s' failed", _fname
);
605 debug("No password specified for PKCS12 file\n");
611 WvString
WvX509Mgr::encode(const WvRSAKey::DumpMode mode
) const
614 return rsa
->encode(mode
);
619 WvString
WvX509Mgr::encode(const WvX509::DumpMode mode
) const
621 return WvX509::encode(mode
);
625 void WvX509Mgr::encode(const WvRSAKey::DumpMode mode
, WvBuf
&buf
) const
628 rsa
->encode(mode
, buf
);
632 void WvX509Mgr::encode(const WvX509::DumpMode mode
, WvBuf
&buf
) const
634 WvX509::encode(mode
, buf
);
638 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode
, WvStringParm encoded
)
641 rsa
->decode(mode
, encoded
);
644 rsa
= new WvRSAKey();
645 rsa
->decode(mode
, encoded
);
650 void WvX509Mgr::decode(const WvX509::DumpMode mode
, WvStringParm encoded
)
652 WvX509::decode(mode
, encoded
);
656 void WvX509Mgr::decode(const WvRSAKey::DumpMode mode
, WvBuf
&encoded
)
659 rsa
->decode(mode
, encoded
);
662 rsa
= new WvRSAKey();
663 rsa
->decode(mode
, encoded
);
668 void WvX509Mgr::decode(const WvX509::DumpMode mode
, WvBuf
&encoded
)
670 WvX509::decode(mode
, encoded
);