Commit dd5c6601 authored by Leigh Stoller's avatar Leigh Stoller

Reorg the credential checking code, and add Geni chain checks.

From: Leigh Stoller <lbstoller@gmail.com>
Date: Wed, 22 May 2013 13:49:33 -0700
Cc: instageni-design@geni.net

So far we have been pretty loose about checking to make sure the
certificate chains obey the Geni rules. These rules include checking to
make sure that only approved entities can sign particular kinds of
credentials. For example; only something known to be a Slice Authority
should be allowed to create a slice and return a slice credential.

The other check we have been lax about, is verifying that the URN namespace
is consistent along the chain from CA to the target. For example, a chain
that starts in Utah:

	URI:urn:publicid:IDN+emulab.net+authority+root

should not be able to sign anything outside its namespace. That is, Utah
should not be able to sign a user or slice credential like:

	urn:publicid:IDN+panther+user+shufeng

This is made more complicated when we introduce subsa certs along the way,
where Utah signs its SA cert and that signs a project slice. In this case
the chain would look something like:

	URI:urn:publicid:IDN+emulab.net+authority+root
	URI:urn:publicid:IDN+emulab.net+authority+sa
        URI:urn:publicid:IDN+emulab.net:testbed+authority+sa
        URI:urn:publicid:IDN+emulab.net:testbed+slice+myslice

There are also scoping rules; A subsa like:

        URI:urn:publicid:IDN+emulab.net:testbed+authority+sa

should not be able to sign:

        URI:urn:publicid:IDN+emulab.net:someotherproject+slice+myslice

The entire cert chain is require to verify this. The CA roots are in the
bundle, and the intermediate certs should be enclosed in the signature
section of the XML document.

We have to make the same check against the user certificate after apache
verifies the chain. For apache (or any SSL server) you have to load the
chain, and as I mentioned in earlier email, this is easy with perl and
python based clients.

With all that said, we do not plan to start rigorous enforcement of the
first check above, and for the second class of checks, we just want to
enforce a simple prefix check until we get our subsa house in order (since
we don't even conform properly yet!).
parent 6a7e03f1
......@@ -350,7 +350,7 @@ sub Resolve($)
return GeniResponse->MalformedArgsResponse();
}
else {
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -477,7 +477,7 @@ sub Register($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -817,7 +817,7 @@ sub Remove($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -887,7 +887,7 @@ sub Shutdown($)
# XXX This should be a slice credential, not a clearinghouse
# credential. But need to wait until new SA is running everywhere.
#
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -941,7 +941,7 @@ sub ListComponents($)
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -995,7 +995,7 @@ sub PostHistoryRecord($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -1195,7 +1195,7 @@ sub PostCRL($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -1248,7 +1248,7 @@ sub List($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -1326,7 +1326,7 @@ sub ListActiveSlivers($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -1412,7 +1412,7 @@ sub ReadHistoryRecords($)
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $credential = CheckCredential($cred, $authority);
my $credential = GeniCredential::CheckCredential($cred, $authority);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -1468,45 +1468,5 @@ sub ReadHistoryRecords($)
return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@results);
}
#
# Initial credential check.
#
sub CheckCredential($;$)
{
my ($credstring, $authority) = @_;
my $credential = GeniCredential->CreateFromSigned($credstring);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
$GeniCredential::CreateFromSignedError);
}
#
# Well formed credentials must now have URNs.
#
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Malformed credentials; missing URNs")
if (! (defined($credential->owner_urn()) &&
defined($credential->target_urn()) &&
GeniHRN::IsValid($credential->owner_urn()) &&
GeniHRN::IsValid($credential->target_urn())));
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_urn() ne $ENV{'GENIURN'}) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This is not your credential");
}
#
# If an authority is provided, the target must match the authority.
#
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This credential is for another authority!")
if (defined($authority) &&
$credential->target_urn() ne $authority->urn());
return $credential;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -173,7 +173,7 @@ sub Resolve($)
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -228,7 +228,7 @@ sub DiscoverResources($)
my $compress = $argref->{'compress'} || 0;
my $version = $argref->{'rspec_version'} || undef;
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -463,7 +463,7 @@ sub GetTicket($;$)
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper characters in rspec");
}
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -2582,7 +2582,7 @@ sub SliverWork($$)
if (! (defined($credstr) && defined($ticketstr))) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -3917,7 +3917,7 @@ sub RenewSlice($)
if (! (defined($credstr))) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4060,7 +4060,7 @@ sub ReleaseTicket($)
if (! (defined($tickstr) && defined($credstr))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4119,7 +4119,7 @@ sub StartSliver($)
if (!defined($cred)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4212,7 +4212,7 @@ sub DeleteSliver($)
if (!defined($cred)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4343,7 +4343,7 @@ sub DeleteSlice($)
if (! defined($credstr)) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($credstr);
my $credential = GeniCredential::CheckCredential($credstr);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4392,7 +4392,7 @@ sub GetSliver($)
if (!defined($cred)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4468,7 +4468,7 @@ sub BindToSlice($)
if (!defined($cred)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4517,7 +4517,7 @@ sub Shutdown($)
if (! (defined($cred))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4589,7 +4589,7 @@ sub ListUsage($)
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4687,7 +4687,7 @@ sub ListHistory($)
if (! (defined($cred))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4736,7 +4736,7 @@ sub SliceStatus($)
if (! (defined($cred))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4820,7 +4820,7 @@ sub SliverTicket($)
if (! (defined($cred))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -4916,7 +4916,7 @@ sub SliverStatus($)
if (!defined($cred)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS);
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -5024,7 +5024,7 @@ sub ListTickets($)
if (! (defined($cred))) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = CheckCredential($cred);
my $credential = GeniCredential::CheckCredential($cred);
return $credential
if (GeniResponse::IsResponse($credential));
......@@ -5691,6 +5691,12 @@ sub GeniExperiment($;$)
require Project;
require Group;
#
# BUG: We need to check the sub auth chain to make sure that
# there the common prefix. Otherwise, a subsa could sign a
# slice credential for someone else.
#
#
# If the slice is from this Emulab (SA), then we are going to create the
......@@ -6083,34 +6089,6 @@ sub UpdateManifest($)
return 0;
}
sub CheckCredential($)
{
my $credential = GeniCredential->CreateFromSigned($_[0]);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
$GeniCredential::CreateFromSignedError);
}
#
# Well formed credentials must now have URNs.
#
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Malformed credentials; missing URNs")
if (! (defined($credential->owner_urn()) &&
defined($credential->target_urn()) &&
GeniHRN::IsValid($credential->owner_urn()) &&
GeniHRN::IsValid($credential->target_urn())));
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_urn() ne $ENV{'GENIURN'}) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This is not your credential");
}
return $credential;
}
sub CheckTicket($$)
{
my $ticket = GeniTicket->CreateFromSignedTicket($_[0]);
......
......@@ -374,7 +374,7 @@ sub DiscoverResources($)
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
my $cred = GeniCredential::CheckCredential($credstr);
push(@$credential_objects, $cred)
if(!GeniResponse::IsResponse($cred));
}
......@@ -1266,7 +1266,7 @@ sub RenewSlice($)
}
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
my $cred = GeniCredential::CheckCredential($credstr);
push(@$credential_objects, $cred)
if(!GeniResponse::IsResponse($cred));
}
......@@ -1478,7 +1478,7 @@ sub UpdateTicket($)
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
my $cred = GeniCredential::CheckCredential($credstr);
push(@$credential_objects, $cred)
if(!GeniResponse::IsResponse($cred));
}
......@@ -1564,7 +1564,7 @@ sub UpdateSliver($)
my $credential_objects = [];
foreach my $credstr (@$credentials) {
my $cred = CheckCredential($credstr);
my $cred = GeniCredential::CheckCredential($credstr);
push(@$credential_objects, $cred)
if(!GeniResponse::IsResponse($cred));
}
......@@ -2146,56 +2146,7 @@ sub CheckCredentials($)
return
GeniResponse->MalformedArgsResponse("Wrong number of credentials");
}
my $credential = GeniCredential->CreateFromSigned($credentials[0]);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
$GeniCredential::CreateFromSignedError);
}
#
# Well formed credentials must now have URNs.
#
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Malformed credentials; missing URNs")
if (! (defined($credential->owner_urn()) &&
defined($credential->target_urn()) &&
GeniHRN::IsValid($credential->owner_urn()) &&
GeniHRN::IsValid($credential->target_urn())));
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_urn() ne $ENV{'GENIURN'}) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This is not your credential");
}
return $credential;
}
sub CheckCredential($)
{
my $credential = GeniCredential->CreateFromSigned($_[0]);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
$GeniCredential::CreateFromSignedError);
}
#
# Well formed credentials must now have URNs.
#
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Malformed credentials; missing URNs")
if (! (defined($credential->owner_urn()) &&
defined($credential->target_urn()) &&
GeniHRN::IsValid($credential->owner_urn()) &&
GeniHRN::IsValid($credential->target_urn())));
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_urn() ne $ENV{'GENIURN'}) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"This is not your credential");
}
return $credential;
return GeniCredential::CheckCredential($credentials[0]);
}
#
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2008-2012 University of Utah and the Flux Group.
# Copyright (c) 2008-2013 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -63,6 +63,7 @@ my $NFREE = "$TB/bin/nfree";
my $OPENSSL = "/usr/bin/openssl";
my $SHA1 = "/sbin/sha1";
my $MKCERT = "$TB/sbin/mksyscert";
my $GENICERTS = "$TB/etc/genicacerts";
# Cache of instances to avoid regenerating them.
my %certificates = ();
......@@ -126,10 +127,9 @@ sub Stringify($)
{
my ($self) = @_;
my $uuid = $self->uuid();
my $hrn = $self->hrn();
my $urn = $self->urn();
return "[GeniCertificate: $uuid, $hrn]";
return "[GeniCertificate: $urn]";
}
# accessors
......@@ -140,11 +140,14 @@ sub expires($) { return undef; }
sub created($) { return field($_[0], "created"); }
sub cert($) { return field($_[0], "cert"); }
sub DN($) { return field($_[0], "DN"); }
sub subject($) { return field($_[0], "subject"); }
sub issuer($) { return field($_[0], "issuer"); }
sub privkey($) { return field($_[0], "privkey"); }
sub revoked($) { return field($_[0], "revoked"); }
sub certfile($) { return field($_[0], "certfile"); }
sub uri($) { return field($_[0], "uri"); }
sub urn($) { return field($_[0], "urn"); }
sub rootcert($) { return $_[0]->{'ROOTCERT'}; }
sub GetCertificate($) { return $_[0]; }
# Kludge for SFA certs.
......@@ -378,7 +381,7 @@ sub LoadFromString($$)
open(STDOUT, ">&PARENT") || die "Cannot redirect stdout";
open(STDERR, ">&PARENT") || die "Cannot redirect stderr";
exec("$OPENSSL x509 -subject -text");
exec("$OPENSSL x509 -subject -issuer -text");
die("*** $0:\n".
" exec openssl x509 failed: $!\n");
}
......@@ -428,7 +431,7 @@ sub LoadFromFile($$)
{
my ($class, $filename) = @_;
if (! open(X509, "$OPENSSL x509 -in $filename -subject -text |")) {
if (! open(X509, "$OPENSSL x509 -in $filename -subject -issuer -text |")) {
print STDERR "Could not start $OPENSSL on $filename\n";
return undef;
}
......@@ -461,6 +464,15 @@ sub LoadFromArray($@)
my $DN = shift(@certlines);
chomp($DN);
# And second line is issuer.
my $issuer = shift(@certlines);
chomp($issuer);
my $subject = $DN;
# Get rid of the tags on both.
$issuer =~ s/^issuer=\s+//;
$subject =~ s/^subject=\s+//;
#
# The text output is next. Look for the URN, URL and UUID in the
# extensions. Stop when we get to the certificate line.
......@@ -517,7 +529,7 @@ sub LoadFromArray($@)
# of places the UUID might be stored (and we continue to store UUIDs
# in multiple places ourselves, to maintain backward compatibility).
# The GPO want UUIDs in a subjectAltName extension (which would have
# been found above), so we use that one if it exists. If it doesn't,
# been found above), so we use that one if it exists. If it does not,
# we'll have to dig...
#
# The uuid that PLC puts in the certificate is not associated with the
......@@ -548,6 +560,8 @@ sub LoadFromArray($@)
$self->{'CERT'}->{'uuid'} = $uuid;
$self->{'CERT'}->{'cert'} = $cert;
$self->{'CERT'}->{'DN'} = $DN;
$self->{'CERT'}->{'subject'} = $subject;
$self->{'CERT'}->{'issuer'} = $issuer;
$self->{'CERT'}->{'privkey'} = undef;
$self->{'CERT'}->{'revoked'} = undef;
$self->{'CERT'}->{'created'} = undef;
......@@ -793,7 +807,7 @@ sub SubjectHash($)
my @result = $self->PipeTo(0, "$OPENSSL x509 -subject_hash -noout");
if (! @result) {
print STDERR "Could not convert $self to subject hash\n";
return undef;
return undef;
}
my $hash = $result[0];
if ($hash =~ /^(\w*)$/) {
......@@ -939,6 +953,164 @@ sub WriteKeyToFile($)
return $filename;
}
#
# Find the root certificate for a single certificate. Optional set of
# chain certs provided.
#
sub VerifySSLChain($@)
{
my ($self, @chaincerts) = @_;
my @pemfiles = ();
my $rootpem = undef;
my ($tempfile, $filename);
if (opendir(DIR, "$GENICERTS")) {
my @files = grep {/^.*\.pem$/} readdir(DIR);
closedir(DIR);
@pemfiles = map("$GENICERTS/$_", @files);
}
else {
print STDERR "Failed to opendir $GENICERTS!\n";
return -1;
}
if (opendir(DIR, "$GENICERTS/local")) {
my @files = grep {/^.*\.pem$/} readdir(DIR);
@pemfiles = (@pemfiles, map("$GENICERTS/local/$_", @files))
if (@files);
closedir(DIR);
}
if (!@pemfiles) {
print STDERR "No CA certs in $GENICERTS!\n";
return -1;
}
#
# Simple optimization; put our own CA at the head of the list.
#
@pemfiles = ("$TB/etc/emulab.pem", @pemfiles);
#
# If there are chain certs, must write those to a file for verify.
#
my $optarg = "";
if (@chaincerts) {
($tempfile, $filename) = tempfile(UNLINK => 1);
foreach my $cert (@chaincerts) {
print $tempfile "-----BEGIN CERTIFICATE-----\n";
print $tempfile $cert->cert();
print $tempfile "-----END CERTIFICATE-----\n";
}
$optarg = "-untrusted $filename";
}
#
# Try with each certificate until we find one that works.
#
foreach my $pem (@pemfiles) {
# Silly taint check.
if ($pem =~ /^(.*)$/) {
$pem = $1;
}
my @result = $self->PipeTo(0, "$OPENSSL verify -CAfile $pem ".
"-purpose sslclient $optarg");
# We should always get something back.
return -1
if (!@result);
# Stupid openssl programs; always exit with zero status.
# Have to look at output.
if ($result[0] =~ /OK$/) {
$rootpem = $pem;
last;
}
}
if (!defined($rootpem)) {
print STDERR "Could not verify $self\n";
return -1;
}
my $rootcert = GeniCertificate->LoadFromFile($rootpem);
if (!defined($rootcert)) {
print STDERR "Could not load CA cert from $rootpem\n";
return -1;
}
$self->{'ROOTCERT'} = $rootcert;
return 0;
}
#
# Make sure that the thing that signed the certificate is really
# listed as the issuer.
#
sub VerifySigner($$)
{
my ($self, $signer) = @_;
return -1
if ($self->issuer() ne $signer->subject());
return 0;
}
#
# Verify the URN namespace of the certificate against the thing that
# we think signed it. At the moment, we are being pretty loose with
# this test; just needs to be a prefix.
#
sub VerifySignerURN($$)
{
my ($self, $signer) = @_;
my $urn = $self->urn();
my $signer_urn = $signer->urn();
return -1
if (! GeniHRN::IsValid($urn));
return -1
if (! GeniHRN::IsValid($signer_urn));
my ($authority, $type, undef) = GeniHRN::Parse($urn);
my ($signer_authority, $signer_type, undef) = GeniHRN::Parse($signer_urn);
return -1
if ($authority !~ /^$signer_authority/);
return 0;
}
#
# Verify the chain with respect to Geni rules.
#
sub VerifyGeniChain($$@)
{
my ($self, $errorstr, @signer_certs) = @_;
my $certificate = $self;
while (@signer_certs) {
my $signer = shift(@signer_certs);
my $urn = $certificate->urn();
my $signer_urn = $signer->urn();
if ($certificate->VerifySigner($signer)) {
$$errorstr =
"signer is invalid for signee: $urn // $signer_urn"
if (defined($errorstr));
return -1;
}
if ($certificate->VerifySignerURN($signer)) {
$$errorstr =
"signer in wrong URN space for signee: $urn // $signer_urn"
if (defined($errorstr));
return -1;
}
$certificate = $signer;
}
return 0;
}
############################################################################
#
# Wrapper for local users.
......
......@@ -41,6 +41,7 @@ use vars qw(@ISA @EXPORT);
use GeniDB;
use GeniCertificate;
use GeniResponse;
use GeniUtil;
use GeniXML;
use GeniHRN;
......@@ -434,7 +435,8 @@ sub CreateFromSigned($$;$)
my ($credential) = $doc->getElementsByTagName("credential");
# Ditto the signatures.
my @signatures = $doc->getElementsByTagName("signatures");
my ($signatures) = $doc->getElementsByTagName("signatures");
my @signatures = $signatures->getElementsByTagName("Signature");
# Dig out the extensions
# now extensions is an xml element.
......@@ -528,14 +530,76 @@ sub CreateFromSigned($$;$)
goto bad;
}
# extract the signer certs
my $cert_nodes = $doc->getElementsByTagName("X509Certificate");
my $signer_certs = [];
foreach my $node (@$cert_nodes) {
my $signer_cert = $node->to_literal();
push(@$signer_certs, $signer_cert);
#
# Break apart the delegation chain, we want to find the root
# credential.
#
my $leaf_cred = $credential;
my $root_cred = $leaf_cred;
my $root_xmlid;