Roxen.git
/
server
/
config_actions
/
make_csr.pike
version
»
Context lines:
10
20
40
80
file
none
3
Roxen.git/server/config_actions/make_csr.pike:1:
+
/*
+
* $id:$
+
*/
-
+
inherit "wizard";
+
+
import Standards.PKCS;
+
import Standards.ASN1.Encode;
+
+
#if 0
+
#define WERROR werror
+
#else
+
#define WERROR(x)
+
#endif
+
+
constant name = "Security//Generate a Certificate Signing Request for an RSA key...";
+
+
constant doc = ("To use an RSA key with your server, you must have a certificate "
+
"for it. You request a certificate by sending a Certificate "
+
"Signing Request to a Certificate Authority, for example Thawte "
+
"or VeriSign.");
+
+
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;
+
}
+
+
return (msg || "" )
+
+ ("<font size=+1>Which key do you want to certify?</font><p>"
+
"<var name=key_file type=string><br>\n"
+
"Where the private key is stored.<br> "
+
"<help><blockquote>"
+
"A filename in the real filesystem, where the private key is stored. "
+
"(The private key is needed to sign the CSR. It is <em>not</em> "
+
"included in the file sent to the Certificate Authority)."
+
"</blockquote></help>");
+
}
+
+
mixed verify_0(object id, object mc)
+
{
+
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>"
+
"<help><blockquote>"
+
"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."
+
"</blockquote></help>"
+
+
"<var name=countryName type=string default=SE><br>"
+
"Your country code<br>\n"
+
"<help><blockquote>"
+
"Your two-letter country code, for example GB (United Kingdom). "
+
"This attribute is required."
+
"</blockquote></help>"
+
+
"<var name=stateOrProvinceName type=string><br>"
+
"State/Province<br>\n"
+
"<help><blockquote>"
+
"The state where you are operating. VeriSign requires this attribute "
+
"to be present for US and Canadian customers. Do not abbreviate."
+
"</blockquote></help>"
+
+
"<var name=localityName type=string default=Stockholm><br>"
+
"City/Locality<br>\n"
+
"<help><blockquote>"
+
"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."
+
"</blockquote></help>"
+
+
"<var name=organizationName type=string default=\"Idonex AB\"><br>"
+
"Organization/Company<br>\n"
+
"<help><blockquote>"
+
"The organization name under which you are registered with some "
+
"national or regional authority."
+
"</blockquote></help>"
+
+
"<var name=organizationUnitName type=string "
+
"default=\"Roxen Development\"><br>"
+
"Organizational unit<br>\n"
+
"<help><blockquote>"
+
"This attribute is optional, and there are no "
+
"specific requirements on the value of this attribute."
+
"</blockquote></help>"
+
+
"<var name=commonName type=string default=\"www.idonex.se\"><br>"
+
"Common Name<br>\n"
+
"This is the DNS name of your server (i.e. the host part of "
+
"the URL).\n"
+
"<help><blockquote>"
+
"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."
+
"</blockquote></help>");
+
}
+
+
mixed page_2(object id, object mc)
+
{
+
return ("<font size=+1>Certificate Attributes?</font><p>"
+
"<help><blockquote>"
+
"The primary parts of a certificate are a Common Name "
+
"and a public key. In addition to these components, a "
+
"certificate may contain other useful information."
+
"</blockquote></help>\n"
+
+
"<var name=emailAddress type=string><br>Email address<br>"
+
"<help><blockquote>"
+
"An email address to be embedded in the certificate."
+
"</blockquote></help>\n");
+
}
+
+
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."
+
+
"<var name=challengePassword type=password> <br>Challenge Password<br>"
+
"<help><blockquote>"
+
"This password could be used if you ever want to revoke "
+
"your certificate. Of course, this depends on the policy of "
+
"your Certificate Authority."
+
"</blockquote></help>\n");
+
}
+
+
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>";
+
+
mapping m = SSL.pem.parse_pem(s);
+
if (!m || !m["RSA PRIVATE KEY"])
+
return "<font color=red>Key file not formatted properly.\n</font>";
+
+
object rsa = RSA.parse_private_key(m["RSA PRIVATE KEY"]);
+
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 = ({ });
+
foreach( ({ "countryName", "localityName", "organizationName",
+
"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]) });
+
}
+
+
csr_attrs->extendedCertificateAttributes =
+
({ Certificate.Attributes(Identifiers.attribute_ids,
+
cert_attrs) });
+
+
object csr = CSR.build_csr(rsa,
+
Certificate.build_distinguished_name(@name),
+
csr_attrs);
+
+
return "<pre>" + SSL.pem.build_pem("CERTIFICATE REQUEST", csr->der())
+
+"</pre>";
+
}
+
+
mixed wizard_done(object id, object mc)
+
{
+
return 0;
+
}
+
+
mixed handle(object id) { return wizard_for(id,0); }
Newline at end of file added.