Optionally use existing private key to generate S/MIME certificate

This commit is contained in:
the-djmaze 2024-02-27 02:19:12 +01:00
parent 97b65465e2
commit 182f884374
6 changed files with 41 additions and 14 deletions

View file

@ -52,10 +52,13 @@ export class IdentityPopupView extends AbstractViewPopup {
if (oData.Result.x509) {
identity.smimeKey(oData.Result.pkey);
identity.smimeCertificate(oData.Result.x509);
} else {
this.submitError(oData.ErrorMessage);
}
}, {
name: identity.name(),
email: identity.email(),
privateKey: identity.smimeKey(),
passphrase: pass.password
});
}

View file

@ -261,7 +261,11 @@ trait Accounts
if (!$oIdentity->FromJSON($this->GetActionParams(), true)) {
throw new ClientException(Notifications::InvalidInputArgument);
}
/* // TODO: verify private key for certificate?
if ($oIdentity->smimeCertificate && $oIdentity->smimeKey) {
new \SnappyMail\SMime\Certificate($oIdentity->smimeCertificate, $oIdentity->smimeKey);
}
*/
$this->IdentitiesProvider()->UpdateIdentity($oAccount, $oIdentity);
return $this->TrueResponse();
}

View file

@ -59,15 +59,13 @@ trait SMime
{
$oAccount = $this->getAccountFromToken();
$sName = $this->GetActionParam('name', '') ?: $oAccount->Name();
$sEmail = $this->GetActionParam('email', '') ?: $oAccount->Email();
$sPassphrase = $this->GetActionParam('passphrase', '');
$this->logMask($sPassphrase);
$cert = new Certificate();
$cert->distinguishedName['commonName'] = $sName;
$cert->distinguishedName['emailAddress'] = $sEmail;
$result = $cert->createSelfSigned($sPassphrase);
$cert->distinguishedName['commonName'] = $this->GetActionParam('name', '') ?: $oAccount->Name();
$cert->distinguishedName['emailAddress'] = $this->GetActionParam('email', '') ?: $oAccount->Email();
$result = $cert->createSelfSigned($sPassphrase, $this->GetActionParam('privateKey', ''));
return $this->DefaultResponse($result ?: false);
}

View file

@ -37,6 +37,16 @@ class Identity implements \JsonSerializable
$this->sEmail = $sEmail;
}
function __get(string $name)
{
if (!\property_exists($this, $name)) {
$name = \substr($name, 1);
}
if (\property_exists($this, $name)) {
return $this->$name;
}
}
function toMime() : \MailSo\Mime\Email
{
return new \MailSo\Mime\Email($this->sEmail, $this->sName);

View file

@ -112,7 +112,11 @@ class Certificate
return \openssl_get_cipher_methods($aliases);
}
public function createSelfSigned(string $passphrase = '') : array
public function createSelfSigned(
#[\SensitiveParameter]
string $passphrase = '',
?string $privateKey = null
) : array
{
$options = array(
'config' => __DIR__ . '/openssl.cnf',
@ -134,7 +138,13 @@ class Certificate
}
$pkey = null; // openssl_pkey_new($options);
$csr = \openssl_csr_new($dn, $pkey, $options);
if ($privateKey) {
$pkey = \openssl_pkey_get_private($privateKey, $passphrase);
if (!$pkey) {
throw new \RuntimeException('OpenSSL pkey: ' . \openssl_error_string());
}
}
$csr = \openssl_csr_new($dn, $pkey, $options);
if ($csr) {
$this->x509 = \openssl_csr_sign(
$csr,
@ -145,13 +155,11 @@ class Certificate
);
if ($this->x509/* && $this->canSign() && $this->canEncrypt()*/) {
$this->pkey = $pkey;
$privatekey = '';
$privateKey || \openssl_pkey_export($pkey, $privateKey, $passphrase);
$certificate = '';
$csrStr = '';
\openssl_pkey_export($pkey, $privatekey, $passphrase);
\openssl_x509_export($this->x509, $certificate);
return array(
'pkey' => $privatekey,
'pkey' => $privateKey,
'x509' => $certificate,
// 'pkcs12' => $this->asPKCS12($pkey, $passphrase/*, array $args = array()*/)
// 'canSign' => $this->canSign(),
@ -167,7 +175,11 @@ class Certificate
}
// returns binary data
public function asPKCS12(string $pass = '', array $args = array()) : string
public function asPKCS12(
#[\SensitiveParameter]
string $pass = '',
array $args = array()
) : string
{
$out = '';
\openssl_pkcs12_export($this->x509, $out, $this->pkey, $pass, $args);

View file

@ -96,7 +96,7 @@
<label>Certificate</label>
<textarea name="smimeCertificate" class="input-xxlarge" rows="14" autofocus="" autocomplete="off" data-bind="value: smimeCertificate"></textarea>
</div>
<div class="control-group" data-bind="hidden:smimeKey">
<div class="control-group" data-bind="hidden:smimeCertificate">
<label></label>
<button type="button" data-bind="click: $root.createSelfSigned" data-i18n="CRYPTO/CREATE_SELF_SIGNED"></button>
</div>