mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-27 19:19:21 +03:00
Added option to create self-signed S/MIME certificate #259
This commit is contained in:
parent
ae4a90bda5
commit
96d08cd418
3 changed files with 212 additions and 0 deletions
39
snappymail/v/0.0.0/app/libraries/RainLoop/Actions/SMime.php
Normal file
39
snappymail/v/0.0.0/app/libraries/RainLoop/Actions/SMime.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Actions;
|
||||
|
||||
use SnappyMail\SMime\OpenSSL;
|
||||
use SnappyMail\SMime\Certificate;
|
||||
|
||||
trait SMime
|
||||
{
|
||||
public function DoGetSMimeCertificate() : array
|
||||
{
|
||||
$result = [
|
||||
'key' => '',
|
||||
'pkey' => '',
|
||||
'cert' => ''
|
||||
];
|
||||
return $this->DefaultResponse(\array_values(\array_unique($result)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be use by Identity
|
||||
*/
|
||||
public function DoCreateSMimeCertificate() : array
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
/*
|
||||
$homedir = \rtrim($this->StorageProvider()->GenerateFilePath(
|
||||
$oAccount,
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::ROOT
|
||||
), '/') . '/.smime';
|
||||
*/
|
||||
$sEmail = $this->GetActionParam('Email', '') ?: $oAccount->Email();
|
||||
|
||||
$cert = new Certificate();
|
||||
$cert->distinguishedName['emailAddress'] = $sEmail;
|
||||
$result = $cert->createSelfSigned('demo');
|
||||
return $this->DefaultResponse($result ?: false);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ trait User
|
|||
use Messages;
|
||||
use Attachments;
|
||||
use Pgp;
|
||||
// use SMime;
|
||||
|
||||
private ?Suggestions $oSuggestionsProvider = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
<?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;
|
||||
|
||||
class Certificate
|
||||
{
|
||||
public
|
||||
$x509 = null,
|
||||
$digest = 'sha256',
|
||||
$cipher = \OPENSSL_CIPHER_AES_256_CBC,
|
||||
$keyBits = 2048,
|
||||
$keyType = \OPENSSL_KEYTYPE_RSA,
|
||||
$days = 1825, // max 5 years, 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
|
||||
),
|
||||
$challengePassphrase; // min 4, max 20 bytes
|
||||
|
||||
// add_entry_by_NID
|
||||
private $NID = [
|
||||
13 => 'commonName',
|
||||
14 => 'countryName',
|
||||
15 => 'localityName',
|
||||
16 => 'stateOrProvinceName',
|
||||
17 => 'organizationName',
|
||||
18 => 'organizationalUnitName',
|
||||
48 => 'emailAddress',
|
||||
];
|
||||
|
||||
/**
|
||||
* A string having the format file://path/to/cert.pem; the named file must contain a PEM encoded certificate
|
||||
* A string containing the content of a certificate, PEM encoded, may start with -----BEGIN CERTIFICATE-----
|
||||
*/
|
||||
function __construct($x509cert = null)
|
||||
{
|
||||
if ($x509cert) {
|
||||
$this->x509 = \openssl_x509_read($x509cert);
|
||||
}
|
||||
}
|
||||
|
||||
function __destruct()
|
||||
{
|
||||
if ($this->x509) {
|
||||
\openssl_x509_free($this->x509);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if a certificate can be used for a particular purpose
|
||||
*/
|
||||
public function checkPurpose($purpose, array $cainfo = array(), $untrustedfile = null)/*: bool|int*/
|
||||
{
|
||||
if ($this->x509) {
|
||||
return \openssl_x509_checkpurpose($this->x509, $purpose, $cainfo, $untrustedfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canSign() : bool
|
||||
{
|
||||
return $this->x509
|
||||
? true === \openssl_x509_checkpurpose($this->x509, \X509_PURPOSE_SMIME_SIGN)
|
||||
: false;
|
||||
}
|
||||
|
||||
public function canEncrypt() : bool
|
||||
{
|
||||
return $this->x509
|
||||
? true === \openssl_x509_checkpurpose($this->x509, \X509_PURPOSE_SMIME_ENCRYPT)
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate in a PEM encoded format string
|
||||
*/
|
||||
public function export($notext = true) : ?string
|
||||
{
|
||||
if ($this->x509) {
|
||||
$output = '';
|
||||
if (\openssl_x509_export($this->x509, $output, $notext)) {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fingerprint or digest of the certificate
|
||||
*/
|
||||
public function fingerprint($hash_algorithm = 'sha1', $raw_output = false)/*: string|bool*/
|
||||
{
|
||||
return $this->x509 ? \openssl_x509_fingerprint($this->x509, $hash_algorithm, $raw_output) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate information as an array
|
||||
*/
|
||||
public function info($shortnames = true) /*: array|bool*/
|
||||
{
|
||||
return $this->x509 ? \openssl_x509_parse($this->x509, $shortnames) : false;
|
||||
}
|
||||
|
||||
public static function getCipherMethods($aliases = false) : array
|
||||
{
|
||||
return \openssl_get_cipher_methods($aliases);
|
||||
}
|
||||
|
||||
public function createSelfSigned($passphrase = null) : array
|
||||
{
|
||||
if ($this->x509) {
|
||||
\openssl_x509_free($this->x509);
|
||||
}
|
||||
|
||||
$configargs = array(
|
||||
'digest_alg' => $this->digest,
|
||||
'private_key_bits' => $this->keyBits,
|
||||
'private_key_type' => $this->keyType,
|
||||
'encrypt_key' => true,
|
||||
'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',
|
||||
);
|
||||
|
||||
$dn = $this->distinguishedName;
|
||||
if (empty($dn['organizationalUnitName'])) {
|
||||
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()*/)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// returns binary data
|
||||
public function asPKCS12($priv_key, $pass = null, array $args = array()) : string
|
||||
{
|
||||
$out = '';
|
||||
\openssl_pkcs12_export($this->x509, $out, $priv_key, $pass, $args);
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue