Zuzu
view release on metacpan or search on metacpan
lib/Zuzu/Module/Secure.pm view on Meta::CPAN
my ( $self, $label ) = @_;
_error( "TypeException: $label expects TlsIdentity" )
if not blessed($self)
or not $self->can('class')
or $self->class->name ne 'TlsIdentity';
return $self->slots;
}
sub _tls_identity_from_pem {
my ( $tls_identity_class, $certificate_pem, $private_key_pem, $password ) = @_;
my $label = 'TlsIdentity.from_pem';
my $cert_pem = _string_arg(
$certificate_pem,
$label,
'String certificate_pem',
);
my $key_pem = _string_arg(
$private_key_pem,
$label,
'String private_key_pem',
);
my $pass = _optional_password_text( $password, $label, 'String password' );
my @blocks = _pem_blocks( $cert_pem, $label );
_parse_x509_der( native_class( name => 'Certificate' ), $blocks[0], $label );
_error( "$label expects PEM private key text" )
if $key_pem !~ /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
return _new_tls_identity(
$tls_identity_class,
_cert_pem => _der_to_pem_certificate( $blocks[0] ),
lib/Zuzu/Module/Secure.pm view on Meta::CPAN
my ( $tls_identity_class, $bytes_value, $password ) = @_;
my $label = 'TlsIdentity.from_pkcs12';
my $bytes = _binary_bytes( $bytes_value, $label, 'BinaryString bytes' );
my $pass = _optional_password_text( $password, $label, 'String password' );
my $pkcs12 = eval { Crypt::OpenSSL::PKCS12->new_from_string($bytes) };
_error( "$label expects PKCS#12 data" ) if not defined $pkcs12;
_error( "$label failed to decrypt PKCS#12 data" )
if not eval { $pkcs12->mac_ok($pass) };
my $cert_pem = eval { $pkcs12->certificate($pass) };
my $key_pem = eval { $pkcs12->private_key($pass) };
_error( "$label expects PKCS#12 data with certificate and private key" )
if not defined $cert_pem or not defined $key_pem;
my $ca_pem = eval { $pkcs12->ca_certificate($pass) } // '';
my @blocks = _pem_blocks( $cert_pem, $label );
return _new_tls_identity(
$tls_identity_class,
_cert_pem => _der_to_pem_certificate( $blocks[0] ),
_key_pem => $key_pem,
_password => '',
lib/Zuzu/Module/Secure.pm view on Meta::CPAN
}
sub _tls_identity_certificate {
my ( $certificate_class, $self ) = @_;
my $state = _tls_identity_state( $self, 'TlsIdentity.certificate' );
my ( $der ) = _pem_blocks( $state->{_cert_pem}, 'TlsIdentity.certificate' );
return _parse_x509_der( $certificate_class, $der, 'TlsIdentity.certificate' );
}
sub _tls_identity_private_key {
my ( $signing_key_class, $self ) = @_;
my $state = _tls_identity_state( $self, 'TlsIdentity.private_key' );
my $options = Zuzu::Value::Dict->new(
map => {
format => 'pem',
password => $state->{_password},
},
);
return eval {
_signing_import_private(
$signing_key_class,
$state->{_key_pem},
$options,
);
} // do {
_error(
'TlsIdentity.private_key only supports Ed25519, ECDSA P-256, '
. 'ECDSA P-384, and ECDSA P-521 private keys',
);
};
}
sub _signing_generate {
my ( $signing_key_class, $algorithm ) = @_;
my $label = 'SigningKey.generate';
$algorithm = _signing_algorithm( $algorithm, $label );
lib/Zuzu/Module/Secure.pm view on Meta::CPAN
my $tls_identity_class;
$tls_identity_class = native_class(
name => 'TlsIdentity',
static_methods => {
from_pem => native_function(
name => 'from_pem',
native => sub {
my (
$self,
$certificate_pem,
$private_key_pem,
$password,
) = @_;
return _tls_identity_from_pem(
$tls_identity_class,
$certificate_pem,
$private_key_pem,
$password,
);
},
),
from_pkcs12 => native_function(
name => 'from_pkcs12',
native => sub {
my ( $self, $bytes, $password ) = @_;
return _tls_identity_from_pkcs12(
$tls_identity_class,
lib/Zuzu/Module/Secure.pm view on Meta::CPAN
certificate => native_function(
name => 'certificate',
native => sub {
my ( $self ) = @_;
return _tls_identity_certificate(
$certificate_class,
$self,
);
},
),
private_key => native_function(
name => 'private_key',
native => sub {
my ( $self ) = @_;
return _tls_identity_private_key(
$signing_key_class,
$self,
);
},
),
},
);
return {
Secure => $secure_class,
stdlib/modules/std/secure.zzm view on Meta::CPAN
TLS identity objects are parsed and inspected by C<std/secure> and can
be supplied to C<std/net/http> C<UserAgent> or C<Request> objects for
mutual-TLS client authentication. PEM certificate input may contain a
chain; the first certificate is treated as the leaf certificate. The
full chain is retained internally for HTTP TLS use, but this phase does
not expose a public chain accessor.
=over
=item C<< TlsIdentity.from_pem(String certificate_pem, String private_key_pem, String password = null) >>
Parses PEM identity material and returns a C<TlsIdentity>. C<password>
C<null> means an empty passphrase. Browser hosts accept PEM identities,
but the identity is inert for signing-key extraction.
=item C<< TlsIdentity.from_pkcs12(BinaryString bytes, String password = null) >>
Parses PKCS#12 identity material where supported. C<password> C<null>
means an empty passphrase.
=item C<< TlsIdentity.certificate() >>
Returns the leaf certificate as a C<Certificate>.
=item C<< TlsIdentity.private_key() >>
Returns a C<SigningKey> for supported private-key algorithms.
Unsupported key algorithms throw clearly.
=back
=head2 Secure Random
=over
stdlib/tests/std/secure/_tls_identity.zzs view on Meta::CPAN
is( cert.not_after().epoch(), 2093422440, "identity not_after epoch" );
if ( caps{host} == "browser" ) {
is(
Secure.has( "tls_identity", "pkcs12" ),
false,
"browser does not advertise PKCS#12 TLS identity",
);
like(
exception( function () {
identity.private_key();
} ),
/not supported/,
"browser private_key is unsupported",
);
like(
exception( function () {
TlsIdentity.from_pkcs12( decode(pkcs12_b64), "zuzu-phase11" );
} ),
/not supported/,
"browser rejects PKCS#12 TLS identity",
);
}
else {
is(
Secure.has( "tls_identity", "pkcs12" ),
true,
"host advertises PKCS#12 TLS identity",
);
is(
caps{tls_identity}.contains("pkcs12"),
true,
"capabilities reports PKCS#12 TLS identity",
);
let private_key := identity.private_key();
is( typeof private_key, "SigningKey", "private_key returns SigningKey" );
let message := to_binary("phase 11 tls identity");
let signature := private_key.sign(message);
is(
cert.public_key().verify( message, signature ),
true,
"identity private key matches certificate public key",
);
let pkcs12_identity := TlsIdentity.from_pkcs12(
decode(pkcs12_b64),
"zuzu-phase11",
);
is(
typeof pkcs12_identity,
"TlsIdentity",
"from_pkcs12 returns a TlsIdentity",
);
is(
pkcs12_identity.certificate().serial_number(),
cert.serial_number(),
"PKCS#12 certificate matches PEM certificate",
);
let pkcs12_key := pkcs12_identity.private_key();
is(
pkcs12_identity.certificate().public_key().verify(
message,
pkcs12_key.sign(message),
),
true,
"PKCS#12 private key matches certificate public key",
);
like(
exception( function () {
( run in 1.134 second using v1.01-cache-2.11-cpan-13bb782fe5a )