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 )