Extract public key from PKCS11 keystore to do signature verification - pkcs#11

I'm generating a keypair in a softHSM keystore, and uses it to sign a software.
Now I need to extract the public key and move it to my target.
I can sign and verify with pkcs11-tool, but I have not succeeded with using openssl verifying.
All I get is
80DB511C4A7F0000:error:02000068:rsa routines:ossl_rsa_verify:bad signature:../crypto/rsa/rsa_sign.c:430:
This is the series of commands I use to generate the keys.
softhsm2-util --init-token --free --label "token-label" --so-pin mysecret1 --pin mysecret1
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --login-type so --so-pin mysecret1 --init-pin --new-pin mysecret1
# create a public-private key pair.
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l --token-label token-label -k --key-type rsa:2048 --usage-sign --id 1002 --label rsatest --pin mysecret1
pkcs11-tool --modul /usr/lib/softhsm/libsofthsm2.so --id 1002 --read-object --type pubkey -o rsa.der
openssl ec -pubin -inform DER -in rsa.der -outform PEM -out rsa.pem
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin mysecret1 --sign --id 1002 -m RSA-PKCS --input text.txt --output /tmp/rsa.signature
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --id 1002 --verify -m RSA-PKCS --input-file text.txt --signature-file /tmp/rsa.signature
openssl dgst -sha512 -keyform PEM -verify rsa.pem -signature /tmp/rsa.signature text.txt
I have tried several combinations of PEM and DER files. Also to change the -sha512 parameter.
A demo project with Dockerfile can be found here: https://gitlab.com/kjeld.flarup/consoletest

A little inspired by https://stackoverflow.com/users/589259/maarten-bodewes I searched for RSA-PSS and found that I could specify SHA512 in the mechanism. Then it worked.
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --pin mysecret1 --sign --id 1002 -m SHA512-RSA-PKCS --input text.txt --output /tmp/rsa.signature

Related

How to use command-line tool `openssl` to decrypt ciphertext encripted by Perl module Crypt::DES?

How to use command-line tool openssl to decrypt the ciphertext that was encrypted with Perl module Crypt::DES?
Assume we have a Perl script like this:
#!/usr/bin/perl -w
use strict;
use 5.010;
use Getopt::Long qw(:config no_ignore_case);
use Crypt::CBC;
### initialization
&GetOptions("mode=s" => \(my $mode = ''));
my $secret = q/;[qO7e<_sZmR8Krhf>}]mRY`y)BI8"WEF*2nmL^o'WMKA=uEt1/;
my $key = pack('H*', $secret);
open(my $fh, '>', 'key.bin');
$fh->print($key);
$fh->close();
my $cipher = Crypt::CBC->new(
-key => $key, -cipher => 'DES'
);
### read file
my $filename = shift #ARGV;
open($fh, '<', $filename) or die "$!";
my $cchRead = read($fh, my $buffer, -s $fh);
close($fh);
die "$!" unless defined($cchRead);
### encrypt
if ($mode eq 'encrypt') {
print $cipher->encrypt($buffer);
}
### decrypt
else {
print $cipher->decrypt($buffer);
}
We can use the Perl script like:
$ ./cipher.pl --mode=encrypt foo.txt > foo.encrypted # Encrypt plaintext.
$ ./cipher.pl --mode=decrypt foo.encrypted # Decrypt ciphertext.
My question is how to decrypt foo.encrypted with command-line tool openssl?
I've tried these commands but in vain.
$ openssl enc -des -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-cbc -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-cfb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-cfb1 -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-cfb8 -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ecb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede-cbc -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede-cfb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede-ofb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede3 -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede3-cbc -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede3-cfb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ede3-ofb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des-ofb -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -des3 -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -desx -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
$ openssl enc -desx-cbc -salt -pbkdf2 -pass file:key.bin -d -in 'foo.encrypted'
On my machine, decryption of the ciphertext generated with the Perl script is successful with:
openssl enc -des -md md5 -pass file:key.bin -d -in foo.encrypted
-des is equivalent to -des-cbc and specifies DES in CBC mode. No PBKDF2 is used as key derivation function, but the OpenSSL proprietary EVP_BytesToKey() with MD5 as digest. The expected ciphertext is the concatenation of the ASCII encoding of Salted__, followed by an 8 bytes salt, followed by the actual ciphertext.
Regarding security: DES, EVP_BytesToKey() and MD5 are deprecated and insecure (better choose AES, PBKDF2 and SHA-256).
As a side note, encrypt() returns the raw ciphertext, therefore with Windows the data must be output in binary (e.g. with binmode(STDOUT)) so that the ciphertext is not corrupted by CRLF⇔LF conversions. Alternatively, the ciphertext can be output Base64 encoded (in which case the -a option must be set in the OpenSSL statement).

Golang connect to Postgres using SSL certificate

First of all, question is languate-agnostic. I'm trying to write a simple application that connects to PostgreSQL using SSL.
I created certificates using scripts:
# Create CA private key
openssl genrsa -des3 -out root.key 4096
#Remove a passphrase
openssl rsa -in root.key -out root.key
# Create a root Certificate Authority (CA)
openssl \
req -new -x509 \
-days 365 \
-subj "/CN=localhost" \
-key root.key \
-out root.crt
# Create server key
openssl genrsa -des3 -out server.key 4096
#Remove a passphrase
openssl rsa -in server.key -out server.key
# Create a root certificate signing request
openssl \
req -new \
-key server.key \
-subj "/CN=localhost" \
-text \
-out server.csr
# Create server certificate
openssl \
x509 -req \
-in server.csr \
-text \
-days 365 \
-CA root.crt \
-CAkey root.key \
-CAcreateserial \
-out server.crt
I created a database using:
init.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE TESTING_DATA (
ID SERIAL PRIMARY KEY,
UUID UUID UNIQUE NOT NULL DEFAULT uuid_generate_v4(),
NAME TEXT NOT NULL,
INFO NUMERIC(3, 2)
);
INSERT INTO TESTING_DATA (NAME, INFO)
VALUES
('Notebook', 1),
('Office supplies', 2),
('Pencil', 2),
('Office supplies', 1),
('Eraser', 1),
('Coffee', 1),
('Cookies', 2),
('Puzzles', 5)
;
postgresql.conf
ssl = on
ssl_ca_file = '/etc/postgres/security/root.crt'
ssl_cert_file = '/etc/postgres/security/server.crt'
ssl_key_file = '/etc/postgres/security/server.key'
password_encryption = scram-sha-256
pg_hba.conf
local all all md5
host all all 127.0.0.1/32 md5
hostssl all all 0.0.0.0/0 cert clientcert=1
Dockerfile
FROM postgres:12-alpine
ENV POSTGRES_USER=pguser
ENV POSTGRES_PASSWORD=pgpassword
ENV POSTGRES_DB=securitylearning
COPY pg_hba.conf postgresql.conf /etc/postgresql/config/
COPY --chown=postgres:postgres root.crt server.crt server.key /etc/postgres/security/
COPY init.sql /docker-entrypoint-initdb.d/
EXPOSE 5432
CMD ["postgres", "-c", "config_file=/etc/postgresql/config/postgresql.conf", "-c", "hba_file=/etc/postgresql/config/pg_hba.conf"]
I launched a container, I ensured that from the container itself I can connect to database and select something from the table.
I created a simple program:
server.go
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func main() {
connection := fmt.Sprint(
" host=localhost",
" port=5432",
" user=pguser",
" dbname=securitylearning",
" sslmode=verify-full",
" sslrootcert=root.crt",
" sslkey=client.key",
" sslcert=client.crt",
)
db, err := sql.Open("postgres", connection)
defer db.Close()
if err != nil {
panic(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
row := db.QueryRow("SELECT * FROM TESTING_DATA")
fmt.Println(row)
}
I tried to:
place files root.crt, server.crt, server.key next to the compiled binary and add to the connection string in go file sslrootcert, sslcert, sslkey respectively
place same files, but with names root.crt, postgresql.crt, postgresql.key in ~/.postgresql/ directory, because pq uses them by default.
For now, it's not working. I randomly get one of those two errors:
read: connection reset by peer
or
EOF
Could you please help? What am I missing here? Or could you point me to some resources? Thanks in advance.
Update 1
Thanks to suggestion in comments, I created client key and certificate, using
# Create client key
openssl genrsa -out client.key 4096
#Remove a passphrase
openssl rsa -in client.key -out client.key
# Create client certificate signing request
openssl \
req -new \
-key client.key \
-subj "/CN=172.17.0.2" \
-out client.csr
# Create client certificate
openssl \
x509 -req \
-in client.csr \
-CA root.crt \
-CAkey root.key \
-CAcreateserial \
-days 365 \
-text \
-out client.crt
I'm using 172.17.0.2 in CN, because it's host IP from docker container's perspective.
I've tried both:
using following keys in connection string from program
" sslrootcert=root.crt",
" sslkey=client.key",
" sslcert=client.crt",
copying root.crt, client.key, client.srt to ~/.postgresql/, trying psql with
psql "host=localhost port=5432 user=pguser dbname=securitylearning sslmode=verify-full sslrootcert=root.crt sslkey=client.key sslcert=client.crt"
or without password.
Both ways still fail to connect. In psql case I get error
psql: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.
Thanks to suggestions in comments I managed to solve it.
First of all, as suggested, I stepped back and tried to proceed with smaller steps. Such as, securely connect with psql from host.
Mistake 1
I forgot to add the following property to postgresql.conf
listen_addresses = '*'
The documentation says:
If the list is empty, the server does not listen on any IP interface at all, in which case only Unix-domain sockets can be used to connect to it.
Mistake 2
I fell into a little misconception with certificates and their common names (CN). The following points should be applied to scripts that create certificates. In short:
CN for CA can be anything as long as it is different from the server's
CN. See this question and answer for details
CN for server must be IP/hostname by which we will call server from client (here it's localhost. But if the database would be located at
cooldatabase.com <- this would be server's CN)
CN for client must be username by which we will connect (here, it's
pguser)
When I fixed these two issues - I managed to connect via both psql and go program! Also, the default postgresql.conf is very informative!

Differences between generated x509 certificates in kubernetes v1.10.11 and v1.11.5

I have been creating an amazon AMI with kubernetes installed on it to use as a worker node in EKS, I install the kubelet binary from the amazon-eks s3 bucket.
After upgrading from k8s version 1.10.11 to 1.11.5 I noticed a difference in the x509 certificate that is generated when installing kubelet.
If I jump onto one of the worker nodes with 1.10.11 installed and run this command openssl s_client -connect localhost:10250 2>/dev/null | openssl x509 -noout -text I get the following output for X509v3 Subject Alternative Name:
DNS:ip-<my-ip>.eu-central-1.compute.internal, DNS:ip-<my-ip>, IP Address:<my-ip>
whereas, if I run the same command on a worker node with 1.11.5 installed I get the following output for X509v3 Subject Alternative Name:
DNS:ip-<my-ip>
The only change between the two nodes is the version of kubernetes installed.
Am I missing anything that is now required as of version 1.11.x to set the additional Subject Alternative Names as seemed to be previously done in v1.10.x? I require the IP address to be set in the certificate in the format IP Address:<my-ip> which I was getting for free in version 1.10.
FYI I am running kubelet with the following args:
ExecStart=/usr/bin/kubelet \
--address=0.0.0.0 \
--authentication-token-webhook \
--authorization-mode=Webhook \
--allow-privileged=true \
--cloud-provider=aws \
--cluster-dns=DNS_CLUSTER_IP \
--cluster-domain=cluster.local \
--cni-bin-dir=/opt/cni/bin \
--cni-conf-dir=/etc/cni/net.d \
--container-runtime=docker \
--max-pods=MAX_PODS \
--node-ip=INTERNAL_IP \
--network-plugin=cni \
--pod-infra-container-image=602401143452.dkr.ecr.REGION.amazonaws.com/eks/pause-amd64:3.1 \
--cgroup-driver=cgroupfs \
--register-node=true \
--kubeconfig=/var/lib/kubelet/kubeconfig \
--feature-gates=RotateKubeletServerCertificate=true \
--anonymous-auth=false \
--client-ca-file=CLIENT_CA_FILE \
--node-labels=env=NODE_LABEL
As far as handling the certificates there are not Kubernetes specific differences between 1.10.11 and 1.11.5. It might be related to specific EKS AMI for the nodes that you are using (make sure they are matching)
If not you can manually create the certificates for the kubelet using the same CA as the one in your Kubernetes master. For example:
easyrsa
./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:-<my-ip>,"\
"DNS:ip-<my-ip>.eu-central-1.compute.internal,"\
"DNS:ip-<my-ip>,"\
--days=10000 \
build-server-full server nopass
openssl
Config (csr.conf):
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = <country>
ST = <state>
L = <city>
O = <organization>
OU = <organization unit>
CN = <my-ip>
[ req_ext ]
subjectAltName = #alt_names
[ alt_names ]
DNS.1 = ip-<my-ip>.eu-central-1.compute.internal
DNS.2 = ip-<my-ip>
IP.1 = <my-ip>
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=#alt_names
Create CSR:
$ openssl req -new -key server.key -out server.csr -config csr.conf
Create certificate:
$ openssl x509 -req -in server.csr -CA cluster-ca.crt -CAkey cluster-ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf
cfssl
In a similar fashion you can use cfssl, described here.

How to verify a ECC signature with OpenSSL command?

I have a public key, a 192 bit hash, and a 384 bit signature, all as .txt hex files, and the curve is prime192v1.
What command lines can I use to verify the message with OpenSSL?
For reference, the EC key can be created with the following command:
Create the EC key:
$ openssl ecparam -genkey -name prime192v1 > key.pem
Extract the public key:
$ openssl ec -in key.pem -pubout > pub.pem
Signing the hash of a message and verifying the signature with an EC key can be done the same way as with other key types:
Calculate the hash (use a hash funtion of your choice):
$ openssl dgst -sha256 -binary message.txt > hash.txt
Sign the hash with the private key:
$ openssl pkeyutl -sign -inkey key.pem -in hash.txt > sig.txt
Verify the signature with the public key:
$ openssl pkeyutl -verify -in hash.txt -sigfile sig.txt -inkey key.pem
Signature Verified Successfully

certificates with SDK tools (makecert, pvk2pfx)

I need to make two certificates: CA sert and Server cert.
I use this commands.
makecert -r -pe -n "CN=CACert" -a sha1 -sky signature -cy authority -sv CACert.pvk CACert.cer
certutil -addstore Root TGCA.cer
makecert -pe -n "CN=ServerCert" -a sha1 -sky exchange -ic CACert.cer -iv CACert.pvk -sv ServerCert.pvk ServerCert.cer
pvk2pfx -pvk ServerCert.pvk -spc ServerCert.cer -pfx ServerCert.pfx
Then I import ServerCert.pfx to certificate storage.
Why they do not contain private key in storage?
Why don't you try to generate pfx file by passing the private key password as an argument?
Try it this way
pvk2pfx -pvk ServerCert.pvk -spc ServerCert.cer -pfx ServerCert.pfx -pi password
As the documentation says:
/pi pvkpassword
Specifies the password for the .pvk file.
Source: http://msdn.microsoft.com/en-us/library/windows/hardware/ff550672(v=vs.85).aspx
So, after a long dance with a tambourine I found a solution. Problem was in UI. My goal was to import pfx to localmachine storage. It's impossible to do by starting pxf file from folder.
When pxf imports wihout pvk pass, the internal private key do not imports. Password do not requests when importing to localmachine storage by MMC.
What I made:
Import pxf-file from file explorer to CurrentUser "My" strorage (entering pvk password).
Export certificate from storage to new pxf with password.
Import new pxf to localmachine "My" storage with MMC.
I don't know other ways.