Hello list,After weeks of "unqualified hacking around" on my machine adapting the openxpki installation to suit my needs I thought i'd share the experience and work I have put into this back to you. So, I came up with some modification proposals and setup hints for the other users who want to "try this at home" ;-)
Since this is only my second time posting something to a mailing list, I tried keeping the body text short and have therefore split everything into separate files - I hope MIME messages are'nt a problem...
Ok... Well, what you will find attached here, is: - teststeps.txtA log of the features I have tested, along with an error message, which I cannot explain but doesn't present a problem later on.
- configuration-comments.txtThis file contains instructions how to modify your config files to try out the same things I did.
- modifications.txtThe diffs to the perl modules I modified under /usr/lib/perl5. BTW I'm using 1488 from SVN on Ubuntu 8.04.
- modifications-comments.txt A log with comments to my modifications. - modifedfiles.7zActual copies of my modified files from /usr/lib/perl5. Just in case the diff went wrong and to make the user happy (copy-paste ;-))
I hope these files will make it without problems...A note to the developers regarding the proposals: please don't just adopt my modifications directly - the last time I was contributing to another project this way they did that and my changes broke things in other parts of the software which took them all the way from 1.0-RC1a with several 1.0 delays to 1.20 to discover the problem and fix it ;-( (they've mentioned me in their change log but I'm not very proud of that as you might imagine) Also, I don't know whether some of my changes are fitting into the "design goals" or not...
Anyway, please do a "proof read" before that. Thanks. I hope it will work out for you, have fun and best regards, MarcP.S.: I do scripting only if inevitable and I've used Perl on Win32 only - the last time in 2002. I'm a relatively busy sysad...@win32/64 and *nix-ing in my free time, but I'll do my best on answering questions if there are any. So please don't blame me on the code and/or on reply speed ;-)
1) root user certificate
- login as root and login to key group => ok
- request ca operator certificate: CN=Root DemoCA, UID=root (basic style) => ok
- login as raop and approve ca operator certificate => ok
- login as root and install certificate in browser => ok
- login as root using cert challenge/response and note username displayes upper
right stays "root" instead of whole certificate subject => ok
- go to "my certificates" and see the just requested certificate listed instead
of empty list => ok
2) raop user certificate
- login as raop and request ra operator certificate: CN=Raop DemoCA, UID=raop
(basic style) => ok
- login as root using cert challenge/response and approve raop's csr using
digital signature => fail (sure, i'm a ca operator, but i have to be a ra
operator - i always forget that)
- login as root using "external static" (thank you for this "backdoor") and
approve raop's csr => ok
- login as raop, install certificate and try to login with challenge/response
again, checking the same (username display+certificate doenload) as already
done with root => ok
3) jdoe user certificate (i've renamed him intendedly)
- login as jdoe and request user certificate CN=John Doe, UID=jdoe (basic
style) => ok
- login as raop using cert challenge/response and approve jdoe's csr using
digital signature (the ultimative test) => ok
- login as jdoe, install certificate, relogin using challenge response and
check user+cert as before => ok
4) webserver certificate
- still logged in as jdoe, request webserver certificate using advanced style
=> error but still ok (pending)
==============================================================
I18N_OPENXPKI_CLIENT_HTML_MASON_CREATE_CSR_ERROR_OCCURED_DESC
Errors
* LIST
* [ { 'LABEL' => 'I18N_OPENXPKI_SERVER_API_INVALID_PARAMETER', 'PARAMS' =>
{ 'ERROR' => 'The \'WORKFLOW\' parameter (undef) to
OpenXPKI::Server::API::__ANON__ was an \'undef\', which is not one of the
allowed types: scalar ' } } ]
* SERVICE_MSG
* ERROR
==============================================================
- login as raop using cert challenge/response and approve the csr using digital
signature (i'm getting used to it) => ok
- install certificate on webserver (apache2), configure appropriately, restart
it. (for hints see configuration-comments.txt)
- point browser to ssl url, give it any of the installed user certificates => ok
- choose "certificate via webserver" as authentication method and see if:
- login with all three users works => ok
- username in to right corner is correct (should be UID instead of CN) => ok
- the requested certificates are listed under "My Certificates" => ok
Configuration file changes needed to do the described tests in alphabetical
order:
=== auth.xml ===
Find the following line:
<trust_anchors>your,identifiers,or,realms,here</trust_anchors>
And modify it to:
<trust_anchors>I18N_OPENXPKI_DEPLOYMENT_TEST_DUMMY_CA</trust_anchors>
This is to make signing in with certificate challenge/response possible.
=== config.xml ===
Find the following lines:
<!-- Subsystems defined for this realm -->
<!-- 'id' is the subsystem identifier -->
and verify if you will find the following lines, if not add them (openxpkid
refused starting without that):
<scep id="testscepserver1">
<cert>
<alias>testscepserver1</alias>
<realm>I18N_OPENXPKI_DEPLOYMENT_TEST_DUMMY_CA</realm>
</cert>
<retry_time>000001</retry_time>-->
<scep_client>
<enrollment_role>SCEP Client Enrollment</enrollment_role>
<autoissuance_role>SCEP Client AutoIssuance</autoissuance_role>
</scep_client>
<token super="common/token_config/token{testscepserver1}"/>
</scep>
=== profile.xml ===
for each:
<netscape>
...
add the following line:
<ssl_server> false</ssl_server>
between:
<certificate_type critical="false">
<ssl_client> false</ssl_client>
--> here <--
<smime_client> false</smime_client>
<object_signing> false</object_signing>
<ssl_ca> false</ssl_ca>
<smime_ca> false</smime_ca>
<object_signing_ca>false</object_signing_ca>
</certificate_type>
except for:
<netscape>
<comment critical="false">This is a TLS Server certificate.
Generated with OpenXPKI trustcenter software.</comment>
...
where you should add:
<ssl_server> true</ssl_server>
instead of the above line.
This allows issuing web server certificates where the netscape certificate type
is set to "server".
=== token.xml ===
Search for:
<token id="testdummyca1" super="../token{default}">
<!-- CA key (PEM encoded) -->
<key>/etc/openxpki/instances/trustcenter1/ca/testdummyca1/cakey.pem</key>
<!-- CA passphrase fragments -->
<secret>default</secret>
</token>
and add the following below if it doesn't exist (openxpkid refused starting
without that):
<token id="testscepserver1" super="../token{default}">
<!-- Backend class -->
<backend>OpenXPKI::Crypto::Tool::SCEP</backend>
<!-- Backend shell command -->
<shell>/usr/bin/openca-scep</shell>
<!-- Private key (PEM encoded) -->
<key>/etc/openxpki/instances/trustcenter1/ca/scepdummyserver1/key.pem</key>
<!-- CA passphrase -->
<secret>default</secret>
</token>
=== workflow_validator_certificate_revocation_request.xml ===
Search for:
<param name="trust_anchors" value="identifier1,identifier2,..."/>
and replace it with:
<param name="trust_anchors" value="I18N_OPENXPKI_DEPLOYMENT_TEST_DUMMY_CA"/>
This allows signing CRRs with certificates.
=== workflow_validator_certificate_signing_request.xml ===
Again search for:
<param name="trust_anchors" value="identifier1,identifier2,..."/>
and replace it with:
<param name="trust_anchors" value="I18N_OPENXPKI_DEPLOYMENT_TEST_DUMMY_CA"/>
This allows signing CSRs with certificates.
=== you favorite apache config file goes here ===
Add the following lines there after generating your server certificate to do
client certificate authentication via webserver:
SSLEngine on
SSLCACertificateFile
/etc/openxpki/instances/trustcenter1/ca/testdummyca1/cacert.pem
SSLCARevocationFile /etc/openxpki/instances/trustcenter1/ca/testdummyca1/crl.pem
SSLVerifyClient optional
SSLVerifyDepth 10
SSLProtocol +SSLv3 +TLSv1
SSLCertificateFile /etc/apache2/server.cert.pem
SSLCertificateKeyFile /etc/apache2/server.key.pem
SSLOptions +StdEnvVars +ExportCertData--- Crypto/Profile/Base.pm.orig 2009-07-27 11:18:51.000000000 +0200
+++ Crypto/Profile/Base.pm 2009-07-31 23:41:55.000000000 +0200
@@ -165,6 +165,7 @@
COUNTER => [...@counter, 0,
0],
CONFIG_ID => $cfg_id);
};
+ $config_value =~ s/\s+//g;
if (defined $config_value &&
($config_value eq 'true' || $config_value eq '1')) {
push @values, $bits[$i];
@@ -381,13 +382,14 @@
}
elsif ($path[$#path] eq "netscape/certificate_type")
{
- my @bits = ( "ssl_client", "smime_client", "object_signing",
+ my @bits = ( "ssl_client", "ssl_server", "smime_client",
"object_signing",
"ssl_ca", "smime_ca", "object_signing_ca" );
for (my $i=0; $i < scalar @bits; $i++)
{
my $bit = $self->{config}->get_xpath (XPATH => [...@path,
$bits[$i]],
COUNTER => [...@counter, 0,
0],
CONFIG_ID => $cfg_id);
+ $bit =~ s/\s+//g;
$bit = "1" if ($bit eq "true");
$bit = "0" if ($bit eq "false");
push @values, $bits[$i] if ($bit);
--- Crypto/Backend/OpenSSL/Config.pm.orig 2009-07-28 16:36:47.000000000
+0200
+++ Crypto/Backend/OpenSSL/Config.pm 2009-07-31 23:47:15.000000000 +0200
@@ -582,16 +582,20 @@
}
elsif ($name eq "netscape/certificate_type")
{
- $config .= "nsCertType = $critical";
- my @bits = @{$profile->get_extension("netscape/certificate_type")};
- $config .= "client," if (grep /ssl_client/, @bits);
- $config .= "objsign," if (grep /object_signing/, @bits);
- $config .= "email," if (grep /smime_client/, @bits);
- $config .= "sslCA," if (grep /ssl_client_ca/, @bits);
- $config .= "objCA," if (grep /object_signing_ca/, @bits);
- $config .= "emailCA," if (grep /smime_client_ca/, @bits);
- $config = substr ($config, 0, length ($config)-1); ## remove
trailing ,
- $config .= "\n";
+ my @bits = @{$profile->get_extension("netscape/certificate_type")};
+ # OpenSSL doesn't like it when there is an empty nsCertType config
flag, so check if there is any cert type set (length of array)
+ if (@bits) {
+ $config .= "nsCertType = $critical";
+ $config .= "client," if (grep /ssl_client/, @bits);
+ $config .= "server," if (grep /ssl_server/, @bits);
+ $config .= "objsign," if (grep /object_signing/, @bits);
+ $config .= "email," if (grep /smime_client/, @bits);
+ $config .= "sslCA," if (grep /ssl_client_ca/, @bits);
+ $config .= "objCA," if (grep /object_signing_ca/, @bits);
+ $config .= "emailCA," if (grep /smime_client_ca/, @bits);
+ $config = substr ($config, 0, length ($config)-1); ## remove
trailing ,
+ $config .= "\n";
+ }
}
elsif ($name eq "netscape/comment")
{
--- Crypto/Backend/OpenSSL/Command/pkcs7_get_chain.pm.orig 2009-07-13
23:17:32.000000000 +0200
+++ Crypto/Backend/OpenSSL/Command/pkcs7_get_chain.pm 2009-08-01
00:22:11.000000000 +0200
@@ -147,16 +147,40 @@
while (exists $certs{$subject} && $iterations < $MAX_CHAIN_LENGTH)
{
##! 16: 'while for subject: ' . $subject
$pkcs7 .= $certs{$subject}->{CERT}."\n\n";
last if ($subject eq $certs{$subject}->{ISSUER});
$subject = $certs{$subject}->{ISSUER};
$iterations++;
}
+
+ if ($pkcs7 eq '') {
+ $subject =~ s/\+/\//g;
+ while (exists $certs{$subject} && $iterations < $MAX_CHAIN_LENGTH)
+ {
+ ##! 16: 'while for subject: ' . $subject
+ $pkcs7 .= $certs{$subject}->{CERT}."\n\n";
+ last if ($subject eq $certs{$subject}->{ISSUER});
+ $subject = $certs{$subject}->{ISSUER};
+ $iterations++;
+ }
+ if ($pkcs7 eq '') {
+ $subject =~ /^([^\/]+)\/([^,]+)(.*)$/;
+ $subject = $2 . '/' . $1 . $3;
+ while (exists $certs{$subject} && $iterations < $MAX_CHAIN_LENGTH)
+ {
+ ##! 16: 'while for subject: ' . $subject
+ $pkcs7 .= $certs{$subject}->{CERT}."\n\n";
+ last if ($subject eq $certs{$subject}->{ISSUER});
+ $subject = $certs{$subject}->{ISSUER};
+ $iterations++;
+ }
+ }
+ }
##! 2: "end"
##! 16: 'pkcs7: ' . $pkcs7
if ($pkcs7 eq '') {
OpenXPKI::Exception->throw(
message =>
'I18N_OPENXPKI_CRYPTO_BACKEND_OPENSSL_COMMAND_PKCS7_GET_CHAIN_COULD_NOT_CREATE_CHAIN',
);
}
return $pkcs7;
--- Server/Workflow/Validator/ApprovalSignature.pm.orig 2009-07-21
17:08:00.000000000 +0200
+++ Server/Workflow/Validator/ApprovalSignature.pm 2009-07-31
23:54:10.000000000 +0200
@@ -190,7 +190,7 @@
);
}
##! 16: 'signer subject: ' . $signer_subject
- my $cfg_id = CTX('api')->get_config_id({ ID => $wf->id() });
+ $cfg_id = CTX('api')->get_config_id({ ID => $wf->id() });
if (! defined $cfg_id) {
# as this is called during creation, the cfg id is not defined
# yet, so we use the current one
@@ -250,7 +250,13 @@
}
# FIXME - the code replacing the PKI realms is a duplication form
# Authentication/X509.pm, this should only be in one place ...
- my $realms = CTX('pki_realm');
+ $cfg_id = CTX('api')->get_config_id({ ID => $wf->id() });
+ if (! defined $cfg_id) {
+ # as this is called during creation, the cfg id is not defined
+ # yet, so we use the current one
+ $cfg_id = CTX('api')->get_current_config_id();
+ }
+ my $realms = CTX('pki_realm_by_cfg')->{$cfg_id};
my @pki_realms = keys %{ $realms };
my @trust_anchors;
##! 16: 'pki_realms: ' . Dumper \...@pki_realms
--- Server/Authentication/X509.pm.orig 2009-07-20 00:20:50.000000000 +0200
+++ Server/Authentication/X509.pm 2009-07-31 23:57:51.000000000 +0200
@@ -285,7 +285,17 @@
},
);
}
- my $user = $signer_subject;
+ my $user = '';
+ #extract UID from certificate subject if defined, else use CN if
available, else fallback to whole subject
+ if ($signer_subject =~ /(?<=UID=)([^,\+\/]+)/) {
+ $user = $1;
+ }
+ elsif ($signer_subject =~ /(?<=CN=)([^,\+\/]+)/) {
+ $user = $1;
+ }
+ else {
+ $user = $signer_subject;
+ }
my $role = $cert_db->{ROLE};
if (! defined $role) {
# if the role is not defined in the certificate database,
--- Server/Authentication/ClientX509.pm.orig 2009-07-30 10:59:58.000000000
+0200
+++ Server/Authentication/ClientX509.pm 2009-08-01 00:01:17.000000000 +0200
@@ -133,8 +133,8 @@
},
);
}
- my $notbefore = $cert_info->{BODY}->{NOTBEFORE};
- my $notafter = $cert_info->{BODY}->{NOTAFTER};
+ my $notbefore =
DateTime::Format::DateParse->parse_datetime($cert_info->{BODY}->{NOTBEFORE},
'UTC');
+ my $notafter =
DateTime::Format::DateParse->parse_datetime($cert_info->{BODY}->{NOTAFTER},
'UTC');
my $now = DateTime->now();
if (DateTime->compare($now, $notbefore) == -1) {
##! 16: 'certificate is not yet valid'
@@ -166,6 +166,10 @@
},
);
}
+ #check if certificate subject contains a UID field and if yes return that
instead of the CN offered by the webserver
+ if ($cert_info->{BODY}->{SUBJECT} =~ /(?<=UID=)([^,\+\/]+)/) {
+ $username = $1;
+ }
$self->{ROLE} = $role;
$self->{USER} = $username;Changes in chronological order:
=== ./Crypto/Backend/OpenSSL/Command/pkcs7_get_chain.pm ===
I first started trying to sign in with certificate challenge/response which led
me to the following problem in the debug log:
For some reason the Certificate subject sent by the browser looked like that:
UID=root/CN=Root DemoCA,...
and was compared to the following certificate subject in the database:
CN=Root DemoCA+UID=root,...
I didn't look into the reason why the subject line looked that weird (exchanged
separator, swapped elements)
but just added a few checks and changing the subject line on the fly (replacing
/ with + and swapping the elements)
until it matches. Challenge/response signon was possible after these changes.
Not very clean, but it works for me. ;-)
=== ./Server/Workflow/Validator/ApprovalSignature.pm ===
When trying to approve CSRs with signature I think I received the
I18N_OPENXPKI_SERVER_WORKFLOW_VALIDATOR_APPROVALSIGNATURE_UNTRUSTED_CERTIFICATE
error, even though I had defined the trust anchors
in workflow_validator_certificate_revocation_request.xml and
workflow_validator_certificate_signing_request.xml.
Digging deeper in the debug logs I found that the module tried to load its
config from CTX('pki_realm')
which is not allowed in Workflow context so this call didn't return the config
and so the trust anchor variables didn't get filled.
=== ./Crypto/Profile/Base.pm ===
With Challenge Responese and Signature working, I moved on ot generating server
certificates and trying to authenticate with
client certificates via webserver. This led first to the problem that apache2
rejected my ssl server certificate - but only when
I presented a client certificate to it. Examining more closely the netscape
certificate type field (and after endless searching for
openssl error codes) I found out that there were certificate types set which
must not be set for a server sertificate to fulfil its role.
It must be either not set or have the server bit set.
Examinig the certificate issuance debug logs I found that the XML file was nor
parsed correctly, so I copied the "space eliminator":
$bit =~ s/\s+//g; from elsewhere ;-)
Still - that didn't satisfy me, because now openssl command always failed when
issuing server certificates, and I didn't figure out yet
(and I still didn't) how to actually get the verbose openssl command text
output in the debug logs. But I accidentally stumbled across the
contents of the openssl.cnf file which had the nsCertType line set to:
nsCertType =
So I assumed this was the error, found out later that the @values array was
empty which caused this, and added a security check in:
=== ./Crypto/Backend/OpenSSL/Config.pm ===
if (@bits) {
...
}
so the array was checked for existing elements before any line was written to
the config file.
But this didn't make me happy either, because all other issued certificates had
the nsCertType bit set, only the TLS cert didn't. I don't
know what happens if it isn't set - maybe all purposes are allowed then - so I
decided this to be too risky and added the ssl_server bit
support both in Config.pm and Base.pm.
=== ./Server/Authentication/X509.pm ===
and
=== ./Server/Authentication/ClientX509.pm ===
I first thought asking on the mailing list if it was intended that when logging
on with certificate challenge/response you wouldn't see
workflows and certificates created/issued when logging in using "basic
authentication". When I finally tried logging on with a client
certificate using the webserver I saw that it wasn't: John Doe saw his
certificates again ;-)
So I decided that these two Modules would deserve the "cosmetic" change to
check in the certificate subject for the existence of a UID=
field and if set return its value as user name.
Regarding the ([^,\+\/]+)/): Checking for not + and not , might seem obvoius,
but checking for not / ?
I was hasty after having been hacking around for several weeks and just wanted
to make sure that if some cert subject weirdness is happening
(see at the beginning of this file) this possibility was ruled out too. If
needed change to ([^,\+]+).
modifiedfiles.7z
Description: Binary data
------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________ OpenXPKI-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openxpki-users
