Improved handling to create S/MIME certificates #259

This commit is contained in:
the-djmaze 2024-02-19 01:52:12 +01:00
parent 6fa4dff23b
commit f83b60782a
5 changed files with 279 additions and 43 deletions

View file

@ -29,9 +29,11 @@ trait SMime
\RainLoop\Providers\Storage\Enumerations\StorageType::ROOT
), '/') . '/.smime';
*/
$sName = $this->GetActionParam('name', '') ?: $oAccount->Name();
$sEmail = $this->GetActionParam('email', '') ?: $oAccount->Email();
$cert = new Certificate();
$cert->distinguishedName['commonName'] = $sName;
$cert->distinguishedName['emailAddress'] = $sEmail;
$result = $cert->createSelfSigned('demo');
return $this->DefaultResponse($result ?: false);

View file

@ -1,12 +1,4 @@
<?php
/**
* openssl req -new -newkey rsa:1024 -days 730 -nodes -x509 -keyout www.example.com.key -out www.example.com.crt
*
* Generate private key file (2048 BIT)
* openssl genrsa -aes128 -out private.key -passout pass:ownPassword 2048
* Generate private certificate
* openssl req -x509 -sha256 -new -key private.key -passin pass:ownPassword -days 1825 -out private.cer
*/
namespace SnappyMail\SMime;
@ -16,17 +8,12 @@ class Certificate
$x509 = null,
$digest = 'sha256',
$cipher = \OPENSSL_CIPHER_AES_256_CBC,
$keyBits = 2048,
$keyBits = 4096,
$keyType = \OPENSSL_KEYTYPE_RSA,
$days = 1825, // max 5 years, EV = 1185, DV/OV = 825
$days = 1185, // EV = 1185, DV/OV = 825
$distinguishedName = array(
'commonName' => 'SnappyMail', // max 64 bytes
'countryName' => 'XX', // NL
'localityName' => 'N/A',
'stateOrProvinceName' => 'N/A',
'organizationName' => 'SnappyMail',
'organizationalUnitName' => '',
'emailAddress' => '' // max 64 bytes
'commonName' => '', // max 64 bytes
'emailAddress' => '' // max 64 bytes
),
$challengePassphrase; // min 4, max 20 bytes
@ -54,9 +41,6 @@ class Certificate
function __destruct()
{
if ($this->x509) {
\openssl_x509_free($this->x509);
}
}
/**
@ -121,11 +105,8 @@ class Certificate
public function createSelfSigned($passphrase = null) : array
{
if ($this->x509) {
\openssl_x509_free($this->x509);
}
$configargs = array(
$options = array(
'config' => __DIR__ . '/openssl.cnf',
'digest_alg' => $this->digest,
'private_key_bits' => $this->keyBits,
'private_key_type' => $this->keyType,
@ -133,9 +114,9 @@ class Certificate
'encrypt_key_cipher' => $this->cipher,
// v3_ca = Extensions to use when signing a CA
// usr_cert = Extensions for when we sign normal certs (specified as default)
'x509_extensions' => 'v3_ca', // usr_cert
// v3_req = Extensions to add to a certificate request
// 'req_extensions' => 'v3_req',
'x509_extensions' => 'snappymail_ca', // v3_ca | usr_cert
// Extensions to add to a certificate request
'req_extensions' => 'snappymail_req', // v3_req
);
$dn = $this->distinguishedName;
@ -143,23 +124,36 @@ class Certificate
unset($dn['organizationalUnitName']);
}
$privkey = null; // openssl_pkey_new($configargs);
$csr = \openssl_csr_new($dn, $privkey, $configargs);
$this->x509 = $csr ? \openssl_csr_sign($csr, null, $privkey, $this->days, $configargs) : null;
if ($this->x509) {
$privatekey = '';
$publickey = '';
$csrStr = '';
\openssl_pkey_export($privkey, $privatekey, $passphrase);
\openssl_x509_export($this->x509, $publickey);
\openssl_csr_export($csr, $csrStr);
return array(
'pkey' => $privatekey,
'x509' => $publickey,
'csr' => $csrStr,
// 'pkcs12' => $this->asPKCS12($privkey, $passphrase/*, array $args = array()*/)
$pkey = null; // openssl_pkey_new($options);
$csr = \openssl_csr_new($dn, $pkey, $options);
if ($csr) {
$this->x509 = \openssl_csr_sign(
$csr,
\file_get_contents(__DIR__ . '/snappymail.crt'),
\file_get_contents(__DIR__ . '/snappymail.key'),
$this->days,
$options
);
if ($this->x509/* && $this->canSign() && $this->canEncrypt()*/) {
$privatekey = '';
$certificate = '';
$csrStr = '';
\openssl_pkey_export($pkey, $privatekey, $passphrase);
\openssl_x509_export($this->x509, $certificate);
return array(
'pkey' => $privatekey,
'x509' => $certificate,
// 'pkcs12' => $this->asPKCS12($pkey, $passphrase/*, array $args = array()*/)
// 'canSign' => $this->canSign(),
// 'canEncrypt' => $this->canEncrypt()
);
} else {
throw new \RuntimeException('OpenSSL sign: ' . \openssl_error_string());
}
} else {
throw new \RuntimeException('OpenSSL csr: ' . \openssl_error_string());
}
return [];
}
// returns binary data

View file

@ -0,0 +1,154 @@
HOME = .
openssl_conf = openssl_init
config_diagnostics = 1
oid_section = new_oids
[ new_oids ]
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7
[openssl_init]
providers = provider_sect
ssl_conf = ssl_module
[provider_sect]
default = default_sect
[default_sect]
[ ssl_module ]
system_default = crypto_policy
[ crypto_policy ]
.include = /etc/crypto-policies/back-ends/opensslcnf.config
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./demoCA
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/cacert.pem
serial = $dir/serial
crlnumber = $dir/crlnumber
crl = $dir/crl.pem
private_key = $dir/private/cakey.pem
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = 365
default_crl_days= 30
default_md = default
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
string_mask = utf8only
[ req_distinguished_name ]
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ usr_cert ]
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:true
[ crl_ext ]
authorityKeyIdentifier=keyid:always
[ proxy_cert_ext ]
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
[ tsa ]
default_tsa = tsa_config1
[ tsa_config1 ]
dir = ./demoCA
serial = $dir/tsaserial
crypto_device = builtin
signer_cert = $dir/tsacert.pem
certs = $dir/cacert.pem
signer_key = $dir/private/tsakey.pem
signer_digest = sha256
default_policy = tsa_policy1
other_policies = tsa_policy2, tsa_policy3
digests = sha1, sha256, sha384, sha512
accuracy = secs:1, millisecs:500, microsecs:100
clock_precision_digits = 0
ordering = yes
tsa_name = yes
ess_cert_id_chain = no
ess_cert_id_alg = sha1
[insta]
server = pki.certificate.fi:8700
path = pkix/
recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA"
ignore_keyusage = 1
unprotected_errors = 1
extracertsout = insta.extracerts.pem
ref = 3078
secret = pass:insta
cmd = ir
subject = "/CN=openssl-cmp-test"
newkey = insta.priv.pem
out_trusted = apps/insta.ca.crt
certout = insta.cert.pem
[pbm]
ref = $insta::ref
secret = $insta::secret
[signature]
trusted = $insta::out_trusted
secret =
key = $insta::newkey
cert = $insta::certout
[ir]
cmd = ir
[cr]
cmd = cr
[kur]
cmd = kur
oldcert = $insta::certout
[rr]
cmd = rr
oldcert = $insta::certout
[ snappymail_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
subjectAltName = email:copy
[ snappymail_ca ]
basicConstraints = critical,CA:true
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
subjectAltName = email:copy
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer

View file

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF7TCCA9WgAwIBAgIUTUN7LmHxy9YgRInzdr9AlyD8UsMwDQYJKoZIhvcNAQEL
BQAwgYUxCzAJBgNVBAYTAk5MMRAwDgYDVQQIDAdVdHJlY2h0MRAwDgYDVQQHDAdV
dHJlY2h0MRMwEQYDVQQKDApTbmFwcHlNYWlsMRYwFAYDVQQDDA1zbmFwcHltYWls
LmV1MSUwIwYJKoZIhvcNAQkBFhZzZWN1cml0eUBzbmFwcHltYWlsLmV1MB4XDTI0
MDIxODIzNDEyMFoXDTM0MDUxNjIzNDEyMFowgYUxCzAJBgNVBAYTAk5MMRAwDgYD
VQQIDAdVdHJlY2h0MRAwDgYDVQQHDAdVdHJlY2h0MRMwEQYDVQQKDApTbmFwcHlN
YWlsMRYwFAYDVQQDDA1zbmFwcHltYWlsLmV1MSUwIwYJKoZIhvcNAQkBFhZzZWN1
cml0eUBzbmFwcHltYWlsLmV1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAvxgynsN5CxhfrH0eu1PJEaUz/+oJkCZMeHpYNOiuGiZBSrHpXuGDBWeKgz4n
pl6Voee9KU+itMl6c6tIlY/pIcl7EhnRw/ZaX/wSkJCXHOaL+f7QIZeGeTxI3hU6
8C895ZQQMn6lzsDGJfounCU4YNfXx8VYkoO65zNZlXbwAGoxtK0iQtSbyvs+2oUH
HtqqJ3SUrs1OSFCmOcymSbKHGNcoX5vEx56bRlwl91Uf5zJJvcVejgmLqDxAkxZt
6M3SL1f0VMJyKccJJruGGEjYM7IqlBCtxuNZIk8hGB+4FNOdIKbdo49UBiBKFiAR
TW0hrBwtHmkj2STnS4JGCrQMwhOzRgNq4XcBBCXi+9qLb1H+85qNHPiRiUjVfTmX
MBivThYVdMeRoouv7/EQHdygrJt05mvV6cZYpDi/wTaDNwJroyOKpfFNBjpsIcN+
Lk73p7MXuLOLky2j1RXlTdekvHNMSLcxTHAZAV1BS/tCoLLrtnaXgeZd/kq3KNTY
tdoTyPHXZ2uQsiP65HwXJcCtx8gS8A6hTDBuvAqXpxudoa+sw7mVDV6MUwmfZFLb
+oVnQMFQXe16ZVfBpjeAO21M1Yc7O6QdZHE4PyERAUdtFiWeqCYkiTY2KUYsKL79
1gwZ7Oi+ktf5ULcLOefQ3JHZP0bUFnlUQusT8e6SFVh8IgsCAwEAAaNTMFEwHQYD
VR0OBBYEFIzs5G3S7dv2/zqjs942E9hrYwg1MB8GA1UdIwQYMBaAFIzs5G3S7dv2
/zqjs942E9hrYwg1MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB
AFKDwWx4QbQrvc9u1EUnuTCCU0eB4BQJ9NwDiQ5AiDBguH2AFK8oLEH3hk2EXkp1
yoWLzb+43v71WcOWDzUPQGkMAdyP15B7VqMDQYX93AlvTboztKBw/Mxbvw/by8JO
5Stwyht3EIiIMEHwz9n5yavfeN3ltgYijwM6rMBSiuScfagYJMyYae5KvP77hj1M
O6kbB2vvuqLL/NqxamK2ioGg112Jitlybxkjcq4izujB4pjUwDMg2Z0PN4mdmpIo
/ujHbtGfNoxqUOKIt3AQAVGlg3j0x8NbfN7YLHN11v3AmGj4KbKpIAAxAcK3FgxX
3mZ8CKg4CO6PRYU0LZIVLuyzFz083S6zOE5Y48/3LWG+VQhsBDXHNxsD26FQSeXm
ZWYg7BEMy6J8cweY+l9ktmDpwNK+IMljFs5Az7AwSr3zuScZyJi6ytHdzFoGRc9D
TU4oso9l4/3/G+X/3Vy2uPCNt2MNYafk4nE+lk/WUcKbZqrB8K9XltBR7PxZbpMD
YDScDtX/HoCNq1oPskI6FLdpiW3DccFja2f7qyaAemH1PgAaIM9VSItSaSs1abi7
8mpSw8LdumnPaFPv6JVSS5n4HjWjP2g01reD8Lg9SBqnBAUIs+kvKPHOhfBfDSmS
WTe4EeMGbwGPxCxmR2+uoO2LJFL84xWXtyusS441KUiW
-----END CERTIFICATE-----

View file

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
lxuLGBMOZyy4CruqVloeblEjqz0+3Sw=
-----END PRIVATE KEY-----