1<?php 2 3require('config.php'); 4 5$params = split("/", $_SERVER["PATH_INFO"], 3); 6$realm = $params[1]; 7$cmd = $params[2]; 8$method = $_SERVER["REQUEST_METHOD"]; 9 10unset($user); 11unset($rowid); 12 13if (!empty($_SERVER['PHP_AUTH_DIGEST'])) { 14 $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 15 'uri'=>1, 'response'=>1); 16 $data = array(); 17 $keys = implode('|', array_keys($needed)); 18 preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', 19 $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER); 20 foreach ($matches as $m) { 21 $data[$m[1]] = $m[3] ? $m[3] : $m[4]; 22 unset($needed[$m[1]]); 23 } 24 if ($needed) { 25 error_log("EST: Missing auth parameter"); 26 die('Authentication failed'); 27 } 28 $user = $data['username']; 29 if (strlen($user) < 1) { 30 error_log("EST: Empty username"); 31 die('Authentication failed'); 32 } 33 34 $db = new PDO($osu_db); 35 if (!$db) { 36 error_log("EST: Could not access database"); 37 die("Could not access database"); 38 } 39 40 $sql = "SELECT rowid,password,operation FROM sessions " . 41 "WHERE user='$user' AND realm='$realm'"; 42 $q = $db->query($sql); 43 if (!$q) { 44 error_log("EST: Session not found for user=$user realm=$realm"); 45 die("Session not found"); 46 } 47 $row = $q->fetch(); 48 if (!$row) { 49 error_log("EST: Session fetch failed for user=$user realm=$realm"); 50 die('Session not found'); 51 } 52 $rowid = $row['rowid']; 53 54 $oper = $row['operation']; 55 if ($oper != '5') { 56 error_log("EST: Unexpected operation $oper for user=$user realm=$realm"); 57 die("Session not found"); 58 } 59 $pw = $row['password']; 60 if (strlen($pw) < 1) { 61 error_log("EST: Empty password for user=$user realm=$realm"); 62 die('Authentication failed'); 63 } 64 65 $A1 = md5($user . ':' . $realm . ':' . $pw); 66 $A2 = md5($method . ':' . $data['uri']); 67 $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' . 68 $data['cnonce'] . ':' . $data['qop'] . ':' . $A2); 69 if ($data['response'] != $resp) { 70 error_log("EST: Incorrect authentication response for user=$user realm=$realm"); 71 die('Authentication failed'); 72 } 73} 74 75 76if ($method == "GET" && $cmd == "cacerts") { 77 $fname = "$osu_root/est/$realm-cacerts.pkcs7"; 78 if (!file_exists($fname)) { 79 error_log("EST: cacerts - unknown realm $realm"); 80 die("Unknown realm"); 81 } 82 83 header("Content-Transfer-Encoding: base64"); 84 header("Content-Type: application/pkcs7-mime"); 85 86 $data = file_get_contents($fname); 87 echo wordwrap(base64_encode($data), 72, "\n", true); 88 echo "\n"; 89 error_log("EST: cacerts"); 90} else if ($method == "GET" && $cmd == "csrattrs") { 91 header("Content-Transfer-Encoding: base64"); 92 header("Content-Type: application/csrattrs"); 93 readfile("$osu_root/est/est-attrs.b64"); 94 error_log("EST: csrattrs"); 95} else if ($method == "POST" && $cmd == "simpleenroll") { 96 if (!isset($user) || strlen($user) == 0) { 97 header('HTTP/1.1 401 Unauthorized'); 98 header('WWW-Authenticate: Digest realm="'.$realm. 99 '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); 100 error_log("EST: simpleenroll - require authentication"); 101 die('Authentication required'); 102 } 103 if (!isset($_SERVER["CONTENT_TYPE"])) { 104 error_log("EST: simpleenroll without Content-Type"); 105 die("Missing Content-Type"); 106 } 107 if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) { 108 error_log("EST: simpleenroll - unexpected Content-Type: " . 109 $_SERVER["CONTENT_TYPE"]); 110 die("Unexpected Content-Type"); 111 } 112 113 $data = file_get_contents("php://input"); 114 error_log("EST: simpleenroll - POST data from php://input: " . $data); 115 $req = base64_decode($data); 116 if ($req == FALSE) { 117 error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data"); 118 die("Invalid base64-encoded PKCS#10 data"); 119 } 120 $cadir = "$osu_root/est"; 121 $reqfile = "$cadir/tmp/cert-req.pkcs10"; 122 $f = fopen($reqfile, "wb"); 123 fwrite($f, $req); 124 fclose($f); 125 126 $req_pem = "$reqfile.pem"; 127 if (file_exists($req_pem)) 128 unlink($req_pem); 129 exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM"); 130 if (!file_exists($req_pem)) { 131 error_log("EST: simpleenroll - Failed to parse certificate request"); 132 die("Failed to parse certificate request"); 133 } 134 135 /* FIX: validate request and add HS 2.0 extensions to cert */ 136 $cert_pem = "$cadir/tmp/req-signed.pem"; 137 if (file_exists($cert_pem)) 138 unlink($cert_pem); 139 exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text"); 140 if (!file_exists($cert_pem)) { 141 error_log("EST: simpleenroll - Failed to sign certificate"); 142 die("Failed to sign certificate"); 143 } 144 145 $cert = file_get_contents($cert_pem); 146 $handle = popen("openssl x509 -in $cert_pem -serial -noout", "r"); 147 $serial = fread($handle, 200); 148 pclose($handle); 149 $pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m"; 150 preg_match($pattern, $serial, $matches); 151 if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) { 152 error_log("EST: simpleenroll - Could not get serial number"); 153 die("Could not get serial number"); 154 } 155 $sn = str_replace(":", "", strtoupper($matches['snhex'])); 156 157 $user = "cert-$sn"; 158 error_log("EST: user = $user"); 159 160 $cert_der = "$cadir/tmp/req-signed.der"; 161 if (file_exists($cert_der)) 162 unlink($cert_der); 163 exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER"); 164 if (!file_exists($cert_der)) { 165 error_log("EST: simpleenroll - Failed to convert certificate"); 166 die("Failed to convert certificate"); 167 } 168 $der = file_get_contents($cert_der); 169 $fingerprint = hash("sha256", $der); 170 171 $pkcs7 = "$cadir/tmp/est-client.pkcs7"; 172 if (file_exists($pkcs7)) 173 unlink($pkcs7); 174 exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER"); 175 if (!file_exists($pkcs7)) { 176 error_log("EST: simpleenroll - Failed to prepare PKCS#7 file"); 177 die("Failed to prepare PKCS#7 file"); 178 } 179 180 if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) { 181 error_log("EST: simpleenroll - Failed to update session database"); 182 die("Failed to update session database"); 183 } 184 185 header("Content-Transfer-Encoding: base64"); 186 header("Content-Type: application/pkcs7-mime"); 187 188 $data = file_get_contents($pkcs7); 189 $resp = wordwrap(base64_encode($data), 72, "\n", true); 190 echo $resp . "\n"; 191 error_log("EST: simpleenroll - PKCS#7 response: " . $resp); 192} else { 193 header("HTTP/1.0 404 Not Found"); 194 error_log("EST: Unexpected method or path"); 195 die("Unexpected method or path"); 196} 197 198?> 199