Elfsign Object Signing on Solaris
Don't let this happen to
you—use elfsign!
Solaris elfsign(1) is a command that signs and verifies ELF format executables. That includes not just executable programs (such as ls or cp), but other ELF format files including libraries (such as libnvpair.so) and kernel modules (such as autofs). Elfsign has been available since Solaris 10 and ELF format files distributed with Solaris, since Solaris 10, are signed by either Sun Microsystems or its successor, Oracle Corporation.
When an ELF file is signed, elfsign adds a new section the ELF file, .SUNW_signature, that contains a RSA public key signature and other information about the signer. That is, the algorithm used, algorithm OID, signer CN/OU, and time stamp. The signature section can later be verified by elfsign or other software by matching the signature in the file agains the ELF file contents (excluding the signature).
ELF executable files may also be signed by a 3rd-party or by the customer.
This is useful for verifying the origin and authenticity of executable files installed on a system.
The 3rd-party or customer public key certificate should be installed in /etc/certs/ to allow verification by elfsign.
For currently-released versions of Solaris, only cryptographic framework plugin libraries are verified by Solaris. However, all ELF files may be verified by the elfsign command at any time.
Elfsign Algorithms
Elfsign signatures are created by taking a digest of the ELF section contents, then signing the digest with RSA. To verify, one takes a digest of ELF file and compares with the expected digest that's computed from the signature and RSA public key.
Originally elfsign took a MD5 digest of a SHA-1 digest of the ELF file sections, then signed the resulting digest with RSA. In Solaris 11.1 then Solaris 11.1 SRU 7 (5/2013), the elfsign crypto algorithms available have been expanded to keep up with evolving cryptography. The following table shows the available elfsign algorithms:
Elfsign Algorithm
Solaris Release
Comments
elfsign sign -F rsa_md5_sha1
S10, S11.0, S11.1
Default for S10.
Not recommended*
elfsign sign -F rsa_sha1
S11.1
Default for S11.1.
Not recommended
elfsign sign -F rsa_sha256
S11.1 patch SRU7+
Recommended
___
*Most or all CAs do not accept MD5 CSRs and do not issue MD5
certs due to MD5 hash collision problems.
RSA Key Length.
I recommend using RSA-2048 key length with elfsign is RSA-2048 as the best balance between a long expected "life time", interoperability, and performance.
RSA-2048 keys have an expected lifetime through 2030 (and probably beyond).
For details, see
Recommendation for Key Management: Part 1: General, NIST Publication SP 800-57 part 1 (rev. 3, 7/2012, PDF), tables 2 and 4 (pp. 64, 67).
Step 1: create or obtain a key and cert
The first step in using elfsign is to obtain a key and cert from a public Certificate Authority (CA), or create your own self-signed key and cert. I'll briefly explain both methods.
Obtaining a Certificate from a CA
To obtain a cert from a CA, such as Verisign, Thawte, or Go Daddy (to name a few random examples), you create a private key and a Certificate Signing Request (CSR) file and send it to the CA, following the instructions of the CA on their website. They send back a signed public key certificate. The public key cert, along with the private key you created is used by elfsign to sign an ELF file. The public key cert is distributed with the software and is used by elfsign to verify elfsign signatures in ELF files. You need to request a RSA "Class 3 public key certificate", which is used for servers and software signing. Elfsign uses RSA and we recommend RSA-2048 keys.
The private key and CSR can be generated with openssl(1) or pktool(1) on Solaris.
Here's a simple example that uses pktool to generate a private RSA_2048 key and a CSR for sending to a CA:
$ pktool gencsr keystore=file format=pem outcsr=MYCSR.p10 \
subject="CN=canineswworks.com,OU=Canine SW object signing" \
outkey=MYPRIVATEKEY.key
$ openssl rsa -noout -text -in MYPRIVATEKEY.key
Private-Key: (2048 bit)
modulus:
00:d2:ef:42:f2:0b:8c:96:9f:45:32:fc:fe:54:94:
. . . [omitted for brevity] . . .
c9:c7
publicExponent: 65537 (0x10001)
privateExponent:
26:14:fc:49:26:bc:a3:14:ee:31:5e:6b:ac:69:83:
. . . [omitted for brevity] . . .
81
prime1:
00:f6:b7:52:73:bc:26:57:26:c8:11:eb:6c:dc:cb:
. . . [omitted for brevity] . . .
bc:91:d0:40:d6:9d:ac:b5:69
prime2:
00:da:df:3f:56:b2:18:46:e1:89:5b:6c:f1:1a:41:
. . . [omitted for brevity] . . .
f3:b7:48:de:c3:d9:ce:af:af
exponent1:
00:b9:a2:00:11:02:ed:9a:3f:9c:e4:16:ce:c7:67:
. . . [omitted for brevity] . . .
55:50:25:70:d3:ca:b9:ab:99
exponent2:
00:c8:fc:f5:57:11:98:85:8e:9a:ea:1f:f2:8f:df:
. . . [omitted for brevity] . . .
23:57:0e:4d:b2:a0:12:d2:f5
coefficient:
2f:60:21:cd:dc:52:76:67:1a:d8:75:3e:7f:b0:64:
. . . [omitted for brevity] . . .
06:94:56:d8:9d:5c:8e:9b
$ openssl req -noout -text -in MYCSR.p10
Certificate Request:
Data:
Version: 2 (0x2)
Subject: OU=Canine SW object signing, CN=canineswworks.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:d2:ef:42:f2:0b:8c:96:9f:45:32:fc:fe:54:94:
. . . [omitted for brevity] . . .
c9:c7
Exponent: 65537 (0x10001)
Attributes:
Signature Algorithm: sha1WithRSAEncryption
b3:e8:30:5b:88:37:68:1c:26:6b:45:af:5e:de:ea:60:87:ea:
. . . [omitted for brevity] . . .
06:f9:ed:b4
Secure storage of RSA private key.
The private key needs to be protected if the key signing is used for production
(as opposed to just testing).
That is, protect the key to protect against unauthorized signatures by others.
One method is to use a PIN-protected PKCS#11 keystore.
The private key you generate should be stored in a secure manner, such as in a PKCS#11 keystore using pktool(1). Otherwise others can sign your signature. Other secure key storage mechanisms include a SCA-6000 crypto card, a USB thumb drive stored in a locked area, a dedicated server with restricted access, Oracle Key Manager (OKM), or some combination of these.
I also recommend secure backup of the private key.
Here's an example of generating a private key protected in the PKCS#11 keystore, and a CSR.
$ pktool setpin # use if PIN not set yet
Enter token passphrase: changeme
Create new passphrase:
Re-enter new passphrase:
Passphrase changed.
$ pktool gencsr keystore=pkcs11 label=MYPRIVATEKEY \
format=pem outcsr=MYCSR.p10 \
subject="CN=canineswworks.com,OU=Canine SW object signing"
$ pktool list keystore=pkcs11
Enter PIN for Sun Software PKCS#11 softtoken:
Found 1 asymmetric public keys.
Key #1 - RSA public key: MYPRIVATEKEY
Here's another example that uses openssl instead of pktool to generate a private key and CSR:
$ openssl genrsa -out cert.key 2048
$ openssl req -new -key cert.key -out MYCSR.p10
Self-Signed Cert
You can use openssl or pktool to create a private key and a self-signed public key certificate.
A self-signed cert is useful for development, testing, and internal use.
The private key created should be stored in a secure manner, as mentioned above.
The following example creates a private key, MYSELFSIGNED.key, and a public key cert, MYSELFSIGNED.pem, using pktool and displays the contents with the openssl command.
$ pktool gencert keystore=file format=pem serial=0xD06F00D lifetime=20-year \
keytype=rsa hash=sha256 outcert=MYSELFSIGNED.pem outkey=MYSELFSIGNED.key \
subject="O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com"
$ pktool list keystore=file objtype=cert infile=MYSELFSIGNED.pem
Found 1 certificates.
1. (X.509 certificate)
Filename: MYSELFSIGNED.pem
ID: c8:24:59:08:2b:ae:6e:5c:bc:26:bd:ef:0a:9c:54:de:dd:0f:60:46
Subject: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com
Issuer: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com
Not Before: Oct 17 23:18:00 2013 GMT
Not After: Oct 12 23:18:00 2033 GMT
Serial: 0xD06F00D0
Signature Algorithm: sha256WithRSAEncryption
$ openssl x509 -noout -text -in MYSELFSIGNED.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3496935632 (0xd06f00d0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com
Validity
Not Before: Oct 17 23:18:00 2013 GMT
Not After : Oct 12 23:18:00 2033 GMT
Subject: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bb:e8:11:21:d9:4b:88:53:8b:6c:5a:7a:38:8b:
. . . [omitted for brevity] . . .
bf:77
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
9e:39:fe:c8:44:5c:87:2c:8f:f4:24:f6:0c:9a:2f:64:84:d1:
. . . [omitted for brevity] . . .
5f:78:8e:e8
$ openssl rsa -noout -text -in MYSELFSIGNED.key
Private-Key: (2048 bit)
modulus:
00:bb:e8:11:21:d9:4b:88:53:8b:6c:5a:7a:38:8b:
. . . [omitted for brevity] . . .
bf:77
publicExponent: 65537 (0x10001)
privateExponent:
0a:06:0f:23:e7:1b:88:62:2c:85:d3:2d:c1:e6:6e:
. . . [omitted for brevity] . . .
9c:e1:e0:0a:52:77:29:4a:75:aa:02:d8:af:53:24:
c1
prime1:
00:ea:12:02:bb:5a:0f:5a:d8:a9:95:b2:ba:30:15:
. . . [omitted for brevity] . . .
5b:ca:9c:7c:19:48:77:1e:5d
prime2:
00:cd:82:da:84:71:1d:18:52:cb:c6:4d:74:14:be:
. . . [omitted for brevity] . . .
5f:db:d5:5e:47:89:a7:ef:e3
exponent1:
32:37:62:f6:a6:bf:9c:91:d6:f0:12:c3:f7:04:e9:
. . . [omitted for brevity] . . .
97:3e:33:31:89:66:64:d1
exponent2:
00:88:a2:e8:90:47:f8:75:34:8f:41:50:3b:ce:93:
. . . [omitted for brevity] . . .
ff:74:d4:be:f3:47:45:bd:cb
coefficient:
4d:7c:09:4c:34:73:c4:26:f0:58:f5:e1:45:3c:af:
. . . [omitted for brevity] . . .
af:01:5f:af:ad:6a:09:bf
Step 2: Sign the ELF File object
By now you should have your private key, and obtained, by hook or crook, a cert (either from a CA or use one you created (a self-signed cert). The next step is to sign one or more objects with your private key and cert. Here's a simple example that creates an object file, signs, verifies, and lists the contents of the ELF signature.
$ echo '#include <stdio.h>\nint main(){printf("Hello\\n");}'>hello.c
$ make hello
cc -o hello hello.c
$ elfsign verify -v -c MYSELFSIGNED.pem -e hello
elfsign: no signature found in hello.
$ elfsign sign -F rsa_sha256 -v -k MYSELFSIGNED.key -c MYSELFSIGNED.pem -e hello
elfsign: hello signed successfully.
format: rsa_sha256.
signer: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com.
signed on: October 17, 2013 04:22:49 PM PDT.
$ elfsign list -f format -e hello
rsa_sha256
$ elfsign list -f signer -e hello
O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com
$ elfsign list -f time -e hello
October 17, 2013 04:22:49 PM PDT
$ elfsign verify -v -c MYSELFSIGNED.key -e hello
elfsign: verification of hello failed.
format: rsa_sha256.
signer: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com.
signed on: October 17, 2013 04:22:49 PM PDT.
Signing using the pkcs11 keystore
To sign the ELF file using a private key in the secure pkcs11 keystore, replace
"-K MYSELFSIGNED.key" in the "elfsign sign" command line with "-T MYPRIVATEKEY",
where MYPRIVATKEY is the pkcs11 token label.
Step 3: Install the cert and test on another system
Just signing the object isn't enough. You need to copy or install the cert and the signed ELF file(s) on another system to test that the signature is OK.
Your public key cert should be installed in /etc/certs.
Use elfsign verify to verify the signature. Elfsign verify checks each cert in /etc/certs until it finds one that matches the elfsign signature in the file. If one isn't found, the verification fails.
Here's an example:
$ su
Password:
# rm /etc/certs/MYSELFSIGNED.key
# cp MYSELFSIGNED.pem /etc/certs
# exit
$ elfsign verify -v hello
elfsign: verification of hello passed.
format: rsa_sha256.
signer: O=Canine Software Works, OU=Self-signed CA, CN=canineswworks.com.
signed on: October 17, 2013 04:24:20 PM PDT.
After testing, package your cert along with your ELF object to allow elfsign verification
after your cert and object are installed or copied.
Under the Hood: elfsign verification
Here's the steps taken to verify a ELF file signed with elfsign.
The steps to sign the file are similar except the private key exponent is used instead of the public key exponent and the .SUNW_signature section is written to the ELF file instead of being read from the file.
Generate a digest (SHA-256) of the ELF file sections.
This digest uses all ELF sections loaded in memory, but excludes the ELF header, the .SUNW_signature section, and the symbol table
Extract the RSA signature (RSA-2048) from the .SUNW_signature section
Extract the RSA public key modulus and public key exponent (65537) from the public key cert
Calculate the expected digest as follows:
signaturepublicKeyExponent % publicKeyModulus
Strip the PKCS#1 padding (most significant bytes) from the above.
The padding is 0x00, 0x01, 0xff, 0xff, . . ., 0xff, 0x00.
If the actual digest == expected digest, the ELF file is verified (OK).
Further Information
elfsign(1), pktool(1), and openssl(1) man pages.
"Signed Solaris 10 Binaries?" blog by Darren Moffat (2005) shows how to use elfsign.
"Simple CLI based CA on Solaris" blog by Darren Moffat (2008) shows how to set up a simple CA for use with self-signed certificates.
"How to Create a Certificate by Using the pktool gencert Command"
System Administration Guide: Security Services
(available at docs.oracle.com)