/usr/share/php/Horde/ActiveSync/Request/ValidateCert.php is in php-horde-activesync 2.19.2-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | <?php
/**
* Horde_ActiveSync_Request_ValidateCertificate::
*
* Portions of this class were ported from the Z-Push project:
* File : wbxml.php
* Project : Z-Push
* Descr : WBXML mapping file
*
* Created : 01.10.2007
*
* � Zarafa Deutschland GmbH, www.zarafaserver.de
* This file is distributed under GPL-2.0.
* Consult COPYING file for details
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2012-2014 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
*/
/**
* ActiveSync Handler for ValidateCertificate requests. Responsible for
* determining if the presented smime certificate is valid.
*
* @license http://www.horde.org/licenses/gpl GPLv2
* NOTE: According to sec. 8 of the GENERAL PUBLIC LICENSE (GPL),
* Version 2, the distribution of the Horde_ActiveSync module in or
* to the United States of America is excluded from the scope of this
* license.
* @copyright 2012-2014 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package ActiveSync
* @internal
*/
class Horde_ActiveSync_Request_ValidateCert extends Horde_ActiveSync_Request_Base
{
const VALIDATECERT_VALIDATECERT = 'ValidateCert:ValidateCert';
const VALIDATECERT_CERTIFICATES = 'ValidateCert:Certificates';
const VALIDATECERT_CERTIFICATE = 'ValidateCert:Certificate';
const VALIDATECERT_CERTIFICATECHAIN = 'ValidateCert:CertificateChain';
const VALIDATECERT_CHECKCRL = 'ValidateCert:CheckCRL';
const VALIDATECERT_STATUS = 'ValidateCert:Status';
const STATUS_SUCCESS = 1;
const STATUS_PROTERR = 2;
const STATUS_SIGERR = 3;
const STATUS_UNTRUSTED = 4;
const STATUS_EXPIRED = 7;
const STATUS_PURPOSE_INVALID = 9;
const STATUS_MISSING_INFO = 10;
const STATUS_UNKNOWN = 17;
/**
* Handle request
*
* @return boolean
* @throws Horde_ActiveSync_Exception
*/
protected function _handle()
{
$this->_logger->info(sprintf(
'[%s] Handling ValidateCertificate command.',
$this->_device->id)
);
if (!$this->_decoder->getElementStartTag(self::VALIDATECERT_VALIDATECERT)) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
$certificates = array();
$chain_certificates = array();
while (($field = ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATES) ? self::VALIDATECERT_CERTIFICATES :
($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATECHAIN) ? self::VALIDATECERT_CERTIFICATECHAIN :
($this->_decoder->getElementStartTag(self::VALIDATECERT_CHECKCRL) ? self::VALIDATECERT_CHECKCRL :
-1)))) != -1) {
if ($field == self::VALIDATECERT_CERTIFICATES) {
while ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATE)) {
$certificates[] = $this->_decoder->getElementContent();
$this->_logger->info('VALIDATE CERT: ' . $certificates[count($certificates) - 1]);
if (!$this->_decoder->getElementEndTag()) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
}
if (!$this->_decoder->getElementEndTag()) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
} elseif ($field == self::VALIDATECERT_CERTIFICATECHAIN) {
while ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATE)) {
$chain_certificates[] = $this->_decoder->getElementContent();
$this->_logger->info('CHAIN CERT: ' . $chain_certificates[count($chain_certificates) - 1]);
if (!$this->_decoder->getElementEndTag()) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
}
if (!$this->_decoder->getElementEndTag()) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
} elseif ($field == self::VALIDATECERT_CHECKCRL) {
if ($checkcrl = $this->_decoder->getElementContent()) {
$this->_logger->info('CRL: ' . $checkcrl);
}
if (!$this->_decoder->getElementEndTag()) {
throw new Horde_ActiveSync_Exception('Protocol Error');
}
}
}
$cert_status = array();
foreach ($certificates as $key => $certificate) {
$cert_der = base64_decode($certificate);
$cert_pem = "-----BEGIN CERTIFICATE-----\n"
. chunk_split(base64_encode($cert_der), 64, "\n")
. "-----END CERTIFICATE-----\n";
// Parsable?
if (!$parsed = openssl_x509_parse($cert_pem, false)) {
$cert_status[$key] = self::STATUS_MISSING_INFO;
continue;
}
// Valid times?
$now = time();
if ($parsed['validFrom_time_t'] >= $now || $parsed['validTo_time_t'] <= $now) {
$cert_status[$key] = self::STATUS_EXPIRED;
continue;
}
// Valid purpose/trusted?
// @TODO: CRL support, CHAIN support
$result = openssl_x509_checkpurpose($cert_pem, X509_PURPOSE_SMIME_SIGN, array($this->_activeSync->certPath));
if ($result === false) {
// @TODO:
// checkpurpose returns false if either the purpose is invalid OR
// the certificate is untrusted, so we should validate the
// trust before we send back any errors.
$cert_status[$key] = self::STATUS_PURPOSE_INVALID;
} elseif ($results == -1) {
// Unspecified error.
$cert_status[$key] = self::STATUS_UNKNOWN;
} else {
// If checkpurpose passes, it's valid AND trusted.
$cert_status[$key] = self::STATUS_SUCCESS;
}
}
$this->_encoder->startWBXML();
$this->_encoder->startTag(self::VALIDATECERT_VALIDATECERT);
$this->_encoder->startTag(self::VALIDATECERT_STATUS);
$this->_encoder->content(1);
$this->_encoder->endTag();
foreach ($certificates as $key => $certificate) {
$this->_encoder->startTag(self::VALIDATECERT_CERTIFICATE);
$this->_encoder->startTag(self::VALIDATECERT_STATUS);
$this->_encoder->content($cert_status[$key]);
$this->_encoder->endTag();
$this->_encoder->endTag();
}
$this->_encoder->endTag();
return true;
}
}
|