00001
00002
00003
00004
00005
00006
00007 #include "wvx509.h"
00008 #include "wvdiriter.h"
00009
00010 #include "pem.h"
00011 #include "x509v3.h"
00012
00013 WvX509Mgr::WvX509Mgr(X509 *_cert)
00014 : debug("X509",WvLog::Debug5), errstr("")
00015 {
00016 err = false;
00017 cert = _cert;
00018 keypair = NULL;
00019 }
00020
00021 WvX509Mgr::WvX509Mgr(WvString dName, int bits, WvRSAKey *_keypair)
00022 : debug("X509",WvLog::Debug5), errstr("")
00023 {
00024 debug("Creating New Certificate for %s\n",dName);
00025 keypair = _keypair;
00026 cert = NULL;
00027 err = false;
00028 createSScert(dName, bits);
00029 }
00030
00031
00032 WvX509Mgr::~WvX509Mgr()
00033 {
00034 X509_free(cert);
00035 }
00036
00037
00038
00039 #ifndef NID_domainComponent
00040 #define NID_domainComponent 391
00041 #endif
00042
00043 #ifndef NID_Domain
00044 #define NID_Domain 392
00045 #endif
00046
00047
00048 static WvString set_name_entry(X509_NAME *name, WvString dn)
00049 {
00050 WvString fqdn(""), force_fqdn("");
00051 X509_NAME_ENTRY *ne = NULL;
00052 int count = 0, nid;
00053
00054 WvStringList l;
00055 l.split(dn, ",");
00056
00057
00058
00059 WvStringList::Iter i(l);
00060 for (i.rewind(); i.next(); )
00061 {
00062 WvString s(*i), sid;
00063 char *cptr, *value;
00064
00065 cptr = s.edit();
00066 value = strchr(cptr, '=');
00067 if (value)
00068 *value++ = 0;
00069 else
00070 value = "NULL";
00071
00072 sid = strlwr(trim_string(cptr));
00073
00074 if (sid == "c")
00075 nid = NID_countryName;
00076 else if (sid == "st")
00077 nid = NID_stateOrProvinceName;
00078 else if (sid == "o")
00079 nid = NID_organizationName;
00080 else if (sid == "ou")
00081 nid = NID_organizationalUnitName;
00082 else if (sid == "cn")
00083 {
00084 nid = NID_commonName;
00085 force_fqdn = value;
00086 force_fqdn.unique();
00087 }
00088 else if (sid == "dc")
00089 {
00090 nid = NID_domainComponent;
00091 if (!!fqdn)
00092 fqdn.append(".");
00093 fqdn.append(value);
00094 }
00095 else if (sid == "domain")
00096 {
00097 nid = NID_Domain;
00098 force_fqdn = value;
00099 force_fqdn.unique();
00100 }
00101 else
00102 nid = NID_domainComponent;
00103
00104 if (!ne)
00105 ne = X509_NAME_ENTRY_create_by_NID(NULL, nid,
00106 V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00107 else
00108 X509_NAME_ENTRY_create_by_NID(&ne, nid,
00109 V_ASN1_APP_CHOOSE, (unsigned char *)value, -1);
00110 if (!ne)
00111 continue;
00112 X509_NAME_add_entry(name, ne, count++, 0);
00113 }
00114
00115 X509_NAME_ENTRY_free(ne);
00116
00117 if (!!force_fqdn)
00118 return force_fqdn;
00119 else
00120 return fqdn;
00121 }
00122
00123
00124 void WvX509Mgr::createSScert(WvString dn, int keysize)
00125 {
00126 EVP_PKEY *pk;
00127 X509_NAME *name = NULL;
00128 X509_EXTENSION *ex = NULL;
00129
00130
00131
00132
00133
00134 int serial = 12345;
00135
00136 WvString serverfqdn;
00137
00138 if (keypair == NULL)
00139 {
00140 debug("Need a new RSA key, so generating it...\n");
00141 keypair = new WvRSAKey(keysize);
00142 debug("Ok, I've got a new RSA keypair\n");
00143 }
00144
00145 if ((pk=EVP_PKEY_new()) == NULL)
00146 {
00147 seterr("Error creating key handler for new certificate");
00148 return;
00149 }
00150 if ((cert=X509_new()) == NULL)
00151 {
00152 seterr("Error creating new X509 object");
00153 return;
00154 }
00155 if (!EVP_PKEY_assign_RSA(pk, keypair->rsa))
00156 {
00157 seterr("Error adding RSA keys to certificate");
00158 return;
00159 }
00160
00161
00162
00163 X509_set_version(cert, 0x2);
00164
00165
00166 ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
00167
00168
00169 X509_gmtime_adj(X509_get_notBefore(cert), 0);
00170
00171
00172
00173
00174 X509_gmtime_adj(X509_get_notAfter(cert), (long)60*60*24*3650);
00175 X509_set_pubkey(cert, pk);
00176
00177 name = X509_get_subject_name(cert);
00178 serverfqdn = set_name_entry(name, dn);
00179
00180 if (!serverfqdn)
00181 serverfqdn = "null.noname.null";
00182
00183 X509_set_issuer_name(cert, name);
00184 X509_set_subject_name(cert, name);
00185
00186
00187 ex = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_cert_type, "server");
00188 X509_add_ext(cert, ex, -1);
00189 X509_EXTENSION_free(ex);
00190
00191 debug("Setting netscape SSL server name extension to %s\n", serverfqdn);
00192
00193
00194 ex = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_ssl_server_name,
00195 serverfqdn.edit());
00196 X509_add_ext(cert, ex, -1);
00197 X509_EXTENSION_free(ex);
00198
00199
00200
00201 ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
00202 "critical,digitalSignature,keyEncipherment");
00203 X509_add_ext(cert, ex, -1);
00204 X509_EXTENSION_free(ex);
00205
00206
00207 if (!X509_sign(cert, pk, EVP_md5()))
00208 {
00209 seterr("Could not self sign the certificate");
00210 X509_free(cert);
00211 EVP_PKEY_free(pk);
00212 return;
00213 }
00214 debug("Certificate for %s created\n", dn);
00215
00216
00217
00218
00219
00220 encodecert();
00221 }
00222
00223 WvString WvX509Mgr::createcertreq(WvString dName, int keysize)
00224 {
00225 EVP_PKEY *pk;
00226 X509_NAME *name = NULL;
00227 X509_REQ *certreq;
00228 WvString pkcs10("");
00229 struct stat stupidstat;
00230
00231 FILE *stupidtmp = tmpfile();
00232
00233
00234
00235 if ( keypair == NULL)
00236 {
00237 keypair = new WvRSAKey(keysize);
00238 }
00239 if ((pk=EVP_PKEY_new()) == NULL)
00240 {
00241 seterr("Error creating key handler for new certificate");
00242 return pkcs10;
00243 }
00244 if ((certreq=X509_REQ_new()) == NULL)
00245 {
00246 seterr("Error creating new PKCS#10 object");
00247 return pkcs10;
00248 }
00249
00250 if (!EVP_PKEY_assign_RSA(pk, keypair->rsa))
00251 {
00252 seterr("Error adding RSA keys to certificate");
00253 return pkcs10;
00254 }
00255 X509_REQ_set_pubkey(certreq, pk);
00256 name = X509_REQ_get_subject_name(certreq);
00257
00258 set_name_entry(name, dName);
00259
00260 X509_REQ_set_subject_name(certreq, name);
00261
00262
00263
00264
00265 PEM_write_X509_REQ(stupidtmp,certreq);
00266
00267
00268 rewind(stupidtmp);
00269
00270 fstat(fileno(stupidtmp),&stupidstat);
00271
00272 pkcs10.setsize(stupidstat.st_size + 1);
00273
00274 fread(pkcs10.edit(),sizeof(char),stupidstat.st_size,stupidtmp);
00275
00276 fclose(stupidtmp);
00277
00278 pkcs10.edit()[stupidstat.st_size] = 0;
00279 X509_REQ_free(certreq);
00280 EVP_PKEY_free(pk);
00281
00282 return pkcs10;
00283 }
00284
00285 void WvX509Mgr::decodecert(WvString encodedcert)
00286 {
00287 int hexbytes = strlen((const char *)encodedcert);
00288 int bufsize = hexbytes/2;
00289 unsigned char *certbuf = new unsigned char[bufsize], *cp = certbuf;
00290 X509 *ct;
00291
00292 unhexify(certbuf,encodedcert);
00293 ct = cert = X509_new();
00294 cert = d2i_X509(&ct, &cp, hexbytes/2);
00295
00296 delete[] certbuf;
00297 }
00298
00299
00300 void WvX509Mgr::encodecert()
00301 {
00302 size_t size;
00303 unsigned char *keybuf, *iend;
00304
00305 size = i2d_X509(cert, NULL);
00306 iend = keybuf = new unsigned char[size];
00307 i2d_X509(cert, &iend);
00308
00309 enccert.setsize(size * 2 +1);
00310 hexify(enccert.edit(), keybuf, size);
00311
00312 delete[] keybuf;
00313 }
00314
00315
00316 bool WvX509Mgr::validate()
00317 {
00318 if (cert != NULL)
00319 {
00320 debug("Peer Certificate:\n");
00321 debug("SubjectDN: %s\n",
00322 X509_NAME_oneline(X509_get_subject_name(cert),0,0));
00323 debug("Issuer: %s\n",
00324 X509_NAME_oneline(X509_get_issuer_name(cert),0,0));
00325
00326
00327 if (X509_cmp_current_time(X509_get_notAfter(cert)) == -1)
00328 {
00329 seterr("Peer certificate has expired!");
00330 return false;
00331 }
00332
00333
00334
00335
00336
00337 }
00338 else
00339 debug("Peer doesn't have a certificate.\n");
00340
00341 return true;
00342 }
00343
00344 bool WvX509Mgr::signedbyCAinfile(WvString certfile)
00345 {
00346 X509_STORE *cert_ctx = NULL;
00347 X509_STORE_CTX csc;
00348 X509_LOOKUP *lookup = NULL;
00349 int result = 0;
00350
00351 cert_ctx = X509_STORE_new();
00352 if (cert_ctx == NULL)
00353 {
00354 seterr("Unable to create Certificate Store Context");
00355 return false;
00356 }
00357
00358 lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_file());
00359 if (lookup == NULL) abort();
00360
00361 if (!X509_LOOKUP_load_file(lookup,certfile,X509_FILETYPE_PEM))
00362 {
00363 X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
00364 }
00365
00366 X509_STORE_CTX_init(&csc,cert_ctx,cert,NULL);
00367 result = X509_verify_cert(&csc);
00368 X509_STORE_CTX_cleanup(&csc);
00369
00370 X509_STORE_free(cert_ctx);
00371
00372 if (result == 1)
00373 {
00374 return true;
00375 }
00376 else
00377 {
00378 return false;
00379 }
00380 }
00381
00382 bool WvX509Mgr::signedbyCAindir(WvString certdir)
00383 {
00384 WvDirIter i(certdir,false);
00385 for (i.rewind(); i.next() ; )
00386 {
00387 if (!signedbyCAinfile(i->fullname))
00388 {
00389 return false;
00390 }
00391 }
00392 return true;
00393 }
00394
00395 bool WvX509Mgr::isinCRL()
00396 {
00397 return true;
00398 }
00399
00400 void WvX509Mgr::dumpcert(WvString outfile, bool append)
00401 {
00402 FILE *certout;
00403
00404 if (append)
00405 {
00406 certout = fopen(outfile,"a");
00407 debug("Opening %s for append\n",outfile);
00408 }
00409 else
00410 {
00411 certout = fopen(outfile,"w");
00412 debug("Opening %s for write\n",outfile);
00413 }
00414
00415 if (certout != NULL)
00416 {
00417 debug("Dumping X509 Certificate...\n");
00418 PEM_write_X509(certout,cert);
00419 }
00420 else
00421 {
00422 seterr("Cannot open file for writing");
00423 }
00424
00425 fclose(certout);
00426
00427 return;
00428 }
00429
00430 void WvX509Mgr::dumpkeypair(WvString outfile, bool append)
00431 {
00432 FILE *keyout;
00433 EVP_CIPHER *enc = NULL;
00434
00435 if (append)
00436 {
00437 keyout = fopen(outfile,"a");
00438 debug("Opening %s for append\n",outfile);
00439 }
00440 else
00441 {
00442 keyout = fopen(outfile,"w");
00443 }
00444 if (keyout != NULL)
00445 {
00446 debug("Printing keypair...\n");
00447 (const EVP_CIPHER *)enc = EVP_get_cipherbyname("rsa");
00448 PEM_write_RSAPrivateKey(keyout,keypair->rsa, enc, NULL, 0, NULL, NULL);
00449 }
00450 else
00451 {
00452 seterr("Cannot open file for writing");
00453 }
00454
00455 fclose(keyout);
00456
00457 return;
00458 }
00459
00460 void WvX509Mgr::dumprawkeypair(WvString outfile, bool append)
00461 {
00462 FILE *keyout;
00463 int offset;
00464 struct stat filestat;
00465
00466 if (append)
00467 {
00468 keyout = fopen(outfile,"a");
00469 fstat(fileno(keyout),&filestat);
00470 offset = filestat.st_size;
00471 debug("Opening %s for append\n",outfile);
00472 }
00473 else
00474 {
00475 keyout = fopen(outfile,"w");
00476 offset = 0;
00477 }
00478 if (keyout != NULL)
00479 {
00480 debug("Printing keypair...\n");
00481 RSA_print_fp(keyout,keypair->rsa, offset);
00482 }
00483 else
00484 {
00485 seterr("Cannot open file for writing");
00486 }
00487
00488 fclose(keyout);
00489
00490 return;
00491 }