diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/SMime.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/SMime.php new file mode 100644 index 000000000..d937bd3f1 --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/SMime.php @@ -0,0 +1,39 @@ + '', + '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); + } +} diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php index a004353c7..9c8002368 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php @@ -17,6 +17,7 @@ trait User use Messages; use Attachments; use Pgp; +// use SMime; private ?Suggestions $oSuggestionsProvider = null; diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/smime/certificate.php b/snappymail/v/0.0.0/app/libraries/snappymail/smime/certificate.php new file mode 100644 index 000000000..05efab70b --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/snappymail/smime/certificate.php @@ -0,0 +1,172 @@ + '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; + } +}