63a9a01997-11-30Niels Möller /*
fab8be1999-02-16Per Hedbor  * $Id: make_csr.pike,v 1.9 1999/02/15 23:23:27 per Exp $
63a9a01997-11-30Niels Möller  */ inherit "wizard"; import Standards.PKCS; import Standards.ASN1.Encode; #if 0 #define WERROR werror #else #define WERROR(x) #endif
fab8be1999-02-16Per Hedbor constant name = "Security//Generate a Certificate Signing Request and an RSA key...";
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor constant doc = ("In order to use the SSL on your server, " "you first have to create a random RSA key pair." "One part of the key is kept secret. The " "other part should be submitted to a certificate " "authority, such as Thawte or VeriSign. The " "certificate authority will return the signed " "certificate that is needed to run a secure server.");
63a9a01997-11-30Niels Möller 
e4e7d81997-12-20Henrik Grubbström (Grubba) #if !constant(_Crypto) || !constant(Crypto.rsa)
2e12951997-12-17Henrik Grubbström (Grubba)  constant action_disabled = 1;
e4e7d81997-12-20Henrik Grubbström (Grubba) #else /* constant(_Crypto) && constant(Crypto.rsa) */
2e12951997-12-17Henrik Grubbström (Grubba) 
fab8be1999-02-16Per Hedbor  // Change this page to generate the key...
63a9a01997-11-30Niels Möller mixed page_0(object id, object mc) { string msg; if (id->variables->_error) { msg = "<font color=red>" + id->variables->_error + "</font><p>"; id->variables->_error = 0; }
fab8be1999-02-16Per Hedbor 
63a9a01997-11-30Niels Möller  return (msg || "" )
fab8be1999-02-16Per Hedbor  + ("<font size=+1>How large key do you want to generate?</font><p>" "<b>Key size</b><br>" "<var name=key_size type=int default=1031><br>\n" "<blockquote>" "The desired key size. This is a security parameter; larger " "keys gives better security, but it also makes connecting to " "the server a little slower.<p>" "The largest RSA key that is publicly known to have been broken " "was 130 decimal digits, or about 430 bits large. This " "effort required 500 MIPS-years.<p>" "A key 1000 bits large should be secure enough for most " "applications, but of course you can you use an even larger key " "if you so wish." "</blockquote>" "<b>Key file</b><br>" "<var name=key_file type=string default=ssl3key><br>\n" "<blockquote>" "A filename in the real filesystem, where the secret key should " "be stored." "</blockquote>");
63a9a01997-11-30Niels Möller } mixed verify_0(object id, object mc) {
fab8be1999-02-16Per Hedbor  int key_size = (int) id->variables->key_size; if (key_size < 300) { id->variables->_error = "Keys smaller than 300 bits are ridiculous."; return 1; } if (key_size > 5000) { id->variables->_error = "Keys larger than 5000 bits would take too long to generate."; return 1; } object file = Stdio.File(); object privs = Privs("Storing private RSA key."); if (!file->open(id->variables->key_file, "wct", 0600)) { id->variables->_error = "Could not open file: " + (strerror(file->errno()) || (string) file->errno()) + "."; privs = 0; return 1; } privs = 0; object rsa = Crypto.rsa(); rsa->generate_key(key_size, Crypto.randomness.reasonably_random()->read); string key = Tools.PEM.simple_build_pem ("RSA PRIVATE KEY", Standards.PKCS.RSA.rsa_private_key(rsa)); WERROR(key); if (strlen(key) != file->write(key)) { id->variables->_error = "Write failed: " + (strerror(file->errno()) || (string) file->errno()) + "."; return 1; } destruct(file);
63a9a01997-11-30Niels Möller  if (!file_stat(id->variables->key_file)) { id->variables->_error = "File not found."; return 1; } return 0; } mixed page_1(mixed id, mixed mc) { return ("<font size=+1>Your Distinguished Name?</font><p>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "Your X.501 Distinguished Name consists of a chain of attributes " "and values, where each link in the chain defines more precisely " "who you are. Which attributes are necessary or useful " "depends on what you will use the certificate for, and which " "Certificate Authority you use. This page lets you specify " "the most useful attributes. If you leave a field blank, " "that attribute will be omitted from your name.<p>\n" "Unfortunately, all fields should be in US-ASCII."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>Your country code</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=countryName type=string default=SE><br>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "Your two-letter country code, for example GB (United Kingdom). " "This attribute is required."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>State/Province</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=stateOrProvinceName type=string><br>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "The state where you are operating. VeriSign requires this attribute " "to be present for US and Canadian customers. Do not abbreviate."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>City/Locality</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=localityName type=string default=Stockholm><br>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "The city or locality where you are registered. VeriSign " "requires that at least one of the locality and the state " "attributes are present. Do not abbreviate."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>Organization/Company</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=organizationName type=string default=\"Idonex AB\"><br>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "The organization name under which you are registered with some " "national or regional authority."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>Organizational unit</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=organizationUnitName type=string " "default=\"Roxen Development\"><br>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "This attribute is optional, and there are no " "specific requirements on the value of this attribute."
fab8be1999-02-16Per Hedbor  "</blockquote>"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<b>Common Name</b><br>\n"
63a9a01997-11-30Niels Möller  "<var name=commonName type=string default=\"www.idonex.se\"><br>" "This is the DNS name of your server (i.e. the host part of " "the URL).\n"
fab8be1999-02-16Per Hedbor  "<blockquote>"
63a9a01997-11-30Niels Möller  "Browsers will compare the URL they are connecting to with " "the Common Name in the server's certificate, and warn the user " "if they don't match.<p>" "Some Certificate Authorities allow wild cards in the Common " "Name. This means that you can have a certificate for " "<tt>*.idonex.se</tt> which will match all servers at Idonex." "Thawte allows wild card certificates, while VeriSign does not."
fab8be1999-02-16Per Hedbor  "</blockquote>");
63a9a01997-11-30Niels Möller } mixed page_2(object id, object mc) { return ("<font size=+1>Certificate Attributes?</font><p>"
fab8be1999-02-16Per Hedbor  "<blockquote>"
b098b81998-04-21Niels Möller  "An X.509 certificate associates a Common Name\n" "with a public key. Some certificate authorities support\n" "\"extended certificates\", defined in PKCS#10. An extended\n" "certificate may contain other useful information associated\n" "with the name and the key. This information is signed by the\n" "CA, together with the X.509 certificate.\n"
fab8be1999-02-16Per Hedbor  "</blockquote>\n"
63a9a01997-11-30Niels Möller 
fab8be1999-02-16Per Hedbor  "<br><b>Email address</b><br><var name=emailAddress type=string>" "<blockquote>"
63a9a01997-11-30Niels Möller  "An email address to be embedded in the certificate."
fab8be1999-02-16Per Hedbor  "</blockquote>\n");
63a9a01997-11-30Niels Möller } mixed page_3(object id, object mc) { return ("<font size=+1>CSR Attributes?</font><p>" "At last, you can add attributes to the Certificate Signing " "Request, which are meant for the Certificate Authority " "and are not included in the issued Certificate."
fab8be1999-02-16Per Hedbor  "<p><b>Challenge Password</b><br>" "<var name=challengePassword type=password>" "<blockquote>"
63a9a01997-11-30Niels Möller  "This password could be used if you ever want to revoke " "your certificate. Of course, this depends on the policy of " "your Certificate Authority."
fab8be1999-02-16Per Hedbor  "</blockquote>\n");
63a9a01997-11-30Niels Möller } object trim = Regexp("^[ \t]*([^ \t](.*[^ \t]|))[ \t]*$"); mixed page_4(object id, object mc) { object file = Stdio.File(); object privs = Privs("Reading private RSA key"); if (!file->open(id->variables->key_file, "r")) { privs = 0; return "<font color=red>Could not open key file: " + strerror(file->errno()) + "\n</font>"; } privs = 0; string s = file->read(0x10000); if (!s) return "<font color=red>Could not read private key: " + strerror(file->errno()) + "\n</font>";
5d11861998-04-20Niels Möller  object msg = Tools.PEM.pem_msg()->init(s); object part = msg->parts["RSA PRIVATE KEY"]; if (!part)
63a9a01997-11-30Niels Möller  return "<font color=red>Key file not formatted properly.\n</font>";
5d11861998-04-20Niels Möller  object rsa = RSA.parse_private_key(part->decoded_body());
b5acc31998-04-22Henrik Grubbström (Grubba) 
63a9a01997-11-30Niels Möller  if (!rsa) return "<font color=red>Invalid key.\n</font>"; mapping attrs = ([]); string attr; /* Remove initial and trailing whitespace, and ignore * empty attributes. */ foreach( ({ "countryName", "stateOrProvinceName", "localityName", "organizationName", "organizationUnitName", "commonName", "emailAddress", "challengePassword"}), attr) { if (id->variables[attr]) { array a = trim->split(id->variables[attr]); if (a) attrs[attr] = a[0]; } } array name = ({ });
772dc01998-04-21Niels Möller  foreach( ({ "countryName", "stateOrProvinceName", "localityName", "organizationName",
63a9a01997-11-30Niels Möller  "organizationUnitName", "commonName" }), attr) { if (attrs[attr]) name += ({ ([ attr : asn1_printable_string(attrs[attr]) ]) }); } mapping csr_attrs = ([]); foreach( ({ "challengePassword" }), attr) { if (attrs[attr]) csr_attrs[attr] = ({ asn1_printable_string(attrs[attr]) }); } mapping cert_attrs = ([ ]); foreach( ({ "emailAddress" }), attr) { if (attrs[attr]) cert_attrs[attr] = ({ asn1_IA5_string(attrs[attr]) }); }
b098b81998-04-21Niels Möller  /* Not all CA:s support extendedCertificateAttributes */ if (sizeof(cert_attrs)) csr_attrs->extendedCertificateAttributes = ({ Certificate.Attributes(Identifiers.attribute_ids, cert_attrs) });
63a9a01997-11-30Niels Möller  object csr = CSR.build_csr(rsa, Certificate.build_distinguished_name(@name), csr_attrs);
fab8be1999-02-16Per Hedbor  string re; string res=("<font size=+2>This is your Certificate " "Signing Request.</font><textarea name=csr cols=80 rows=12>"); res += (re=Tools.PEM.simple_build_pem("CERTIFICATE REQUEST", csr->der())); res += "</textarea>"; res += "<p>"; res += ("<p><font size=+1><var type=checkbox name=save></font>" "<b>Save the request in a file:</b><br>" "<blockquote><b>Filename</b><br><var type=string name=save_in_file></blockquote>"); res += ("<p>" "<p><font size=+1><var type=checkbox name=send></font>" "<b>Send the request to Thawte</b><br>") ; return res;
63a9a01997-11-30Niels Möller }
fab8be1999-02-16Per Hedbor  #include "thawte.form"; mapping wizard_done( object id )
63a9a01997-11-30Niels Möller {
fab8be1999-02-16Per Hedbor  if(id->variables->send[0]=='o') { return http_string_answer(sprintf(thawte_form, id->variables->csr)); }
63a9a01997-11-30Niels Möller }
fab8be1999-02-16Per Hedbor  /* https://www.thawte.com/cgi/server/step1.exe */
63a9a01997-11-30Niels Möller mixed handle(object id) { return wizard_for(id,0); }
2e12951997-12-17Henrik Grubbström (Grubba) 
e4e7d81997-12-20Henrik Grubbström (Grubba) #endif /* constant(_Crypto) && constant(Crypto.rsa) */