Source code taken from cacert-20141124.tar.bz2
[cacert.git] / www / gpg.php
1 <? /*
2 LibreSSL - CAcert web application
3 Copyright (C) 2004-2008 CAcert Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */ ?>
18 <?
19 require_once("../includes/loggedin.php");
20 require_once("../includes/lib/general.php");
21 require_once('../includes/notary.inc.php');
22
23 $id = 0; if(array_key_exists('id',$_REQUEST)) $id=intval($_REQUEST['id']);
24 $oldid = $_REQUEST['oldid'] = array_key_exists('oldid',$_REQUEST) ? intval($_REQUEST['oldid']) : 0;
25
26 if($_SESSION['profile']['points'] < 50)
27 {
28 header("location: /account.php");
29 exit;
30 }
31
32 loadem("account");
33
34
35
36 $CSR=""; if(array_key_exists('CSR',$_REQUEST)) $CSR=stripslashes($_REQUEST['CSR']);
37
38
39 if($oldid == "0")
40 {
41 if(array_key_exists('process',$_REQUEST) && $_REQUEST['process'] != "" && $CSR == "")
42 {
43 $_SESSION['_config']['errmsg'] = _("You failed to paste a valid GPG/PGP key.");
44 $id = $oldid;
45 $oldid=0;
46 }
47 }
48
49 $keyid="";
50
51 if(0)
52 {
53 if($_SESSION["profile"]["id"] != 5897)
54 {
55 showheader(_("Welcome to CAcert.org"));
56 echo "The OpenPGP signing system is currently shutdown due to a maintenance. We hope to get it fixed within the next few hours. We are very sorry for the inconvenience.";
57
58 exit(0);
59 }
60 }
61
62
63 function verifyName($name)
64 {
65 if($name == "") return 0;
66
67 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['lname'])) return 1; // John Doe
68 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname']." ".$_SESSION['profile']['lname'])) return 1; // John Joseph Doe
69 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname'][0]." ".$_SESSION['profile']['lname'])) return 1; // John J Doe
70 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname'][0].". ".$_SESSION['profile']['lname'])) return 1; // John J. Doe
71
72 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix'])) return 1; // John Doe Jr.
73 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname']." ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix'])) return 1; //John Joseph Doe Jr.
74 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname'][0]." ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix'])) return 1; //John J Doe Jr.
75 if(!strcasecmp($name, $_SESSION['profile']['fname']." ".$_SESSION['profile']['mname'][0].". ".$_SESSION['profile']['lname']." ".$_SESSION['profile']['suffix'])) return 1; //John J. Doe Jr.
76
77 return 0;
78 }
79
80 function verifyEmail($email)
81 {
82 if($email == "") return 0;
83 if(mysql_num_rows(mysql_query("select * from `email` where `memid`='".$_SESSION['profile']['id']."' and `email`='".mysql_real_escape_string($email)."' and `deleted`=0 and `hash`=''")) > 0) return 1;
84 return 0;
85 }
86
87
88
89 $ToBeDeleted=array();
90 $state=0;
91 if($oldid == "0" && $CSR != "")
92 {
93 if(!array_key_exists('CCA',$_REQUEST))
94 {
95 showheader(_("My CAcert.org Account!"));
96 echo _("You did not accept the CAcert Community Agreement (CCA), hit the back button and try again.");
97 showfooter();
98 exit;
99 }
100
101 $err = runCommand('mktemp --directory /tmp/cacert_gpg.XXXXXXXXXX',
102 "",
103 $tmpdir);
104 if (!$tmpdir)
105 {
106 $err = true;
107 }
108
109 if (!$err)
110 {
111 $err = runCommand("gpg --with-colons --homedir $tmpdir 2>&1",
112 clean_gpgcsr($CSR),
113 $gpg);
114
115 shell_exec("rm -r $tmpdir");
116 }
117
118 if ($err)
119 {
120 showheader(_("Welcome to CAcert.org"));
121
122 echo "<p style='color:#ff0000'>"._("There was an error parsing your key.")."</p>";
123 unset($_REQUEST['process']);
124 $id = $oldid;
125 unset($oldid);
126 exit();
127 }
128
129 $lines = "";
130 $gpgarr = explode("\n", trim($gpg));
131 foreach($gpgarr as $line)
132 {
133 #echo "Line[]: $line <br/>\n";
134 if(substr($line, 0, 3) == "pub" || substr($line, 0, 3) == "uid")
135 {
136 if($lines != "")
137 $lines .= "\n";
138 $lines .= $line;
139 }
140 }
141 $gpg = $lines;
142 $expires = 0;
143 $nerr=0; $nok=0;
144 $multiple = 0;
145
146 $resulttable=_("The following UIDs were found in your key:")."<br/><table border='1'><tr><td>#</td><td>"._("Name")."</td><td>"._("Email")."</td><td>Result</td>";
147 $i=0;
148 $lastvalidemail="";
149 $npubs=0;
150 foreach(explode("\n", $gpg) as $line)
151 {
152 $bits = explode(":", $line);
153 $resulttable.="<tr><td>".++$i."</td>";
154 $name = $comment = "";
155 if($bits[0] == "pub")
156 {
157 $npubs++;
158 }
159 if($npubs>1)
160 {
161 showheader(_("Welcome to CAcert.org"));
162 echo "<font color='#ff0000'>"._("Please upload only one key at a time.")."</font>";
163 unset($_REQUEST['process']);
164 $id = $oldid;
165 unset($oldid);
166 exit();
167 }
168 if($bits[0] == "pub" && (!$keyid || !$when))
169 {
170 $keyid = $bits[4];
171 $when = $bits[5];
172 if($bits[6] != "")
173 $expires = 1;
174 }
175 $name="";
176 $comm="";
177 $mail="";
178 $uidformatwrong=0;
179
180 if(sizeof($bits)<10) $uidformatwrong=1;
181
182 if(preg_match("/\@.*\@/",$bits[9]))
183 {
184 showheader(_("Welcome to CAcert.org"));
185
186 echo "<font color='#ff0000'>"._("Multiple Email Adresses per UID are not allowed.")."</font>";
187 unset($_REQUEST['process']);
188 $id = $oldid;
189 unset($oldid);
190 exit();
191 }
192
193 // Name (Comment) <Email>
194 if(preg_match("/^([^\(\)\[@<>]+) \(([^\(\)@<>]*)\) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
195 {
196 $name=trim(gpg_hex2bin($matches[1]));
197 $nocomment=0;
198 $comm=trim(gpg_hex2bin($matches[2]));
199 $mail=trim(gpg_hex2bin($matches[3]));
200 }
201 // Name <EMail>
202 elseif(preg_match("/^([^\(\)\[@<>]+) <([\w=\/%.-]*\@[\w.-]*|[\w.-]*\![\w=\/%.-]*)>/",$bits[9],$matches))
203 {
204 $name=trim(gpg_hex2bin($matches[1]));
205 $nocomment=1;
206 $comm="";
207 $mail=trim(gpg_hex2bin($matches[2]));
208 }
209 // Unrecognized format
210 else
211 {
212 $nocomment=1;
213 $uidformatwrong=1;
214 }
215 $nameok=verifyName($name);
216 $emailok=verifyEmail($mail);
217
218
219 if($comm != "")
220 $comment[] = $comm;
221
222 $resulttable.="<td bgcolor='#".($nameok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($name)."</td>";
223 $resulttable.="<td bgcolor='#".($emailok?"c0ffc0":"ffc0c0")."'>".sanitizeHTML($mail)."</td>";
224
225 $uidok=0;
226 if($bits[1]=="r")
227 {
228 $rmessage=_("Error: UID is revoked");
229 }
230 elseif($uidformatwrong==1)
231 {
232 $rmessage=_("The format of the UID was not recognized. Please use 'Name (comment) &lt;email@domain>'");
233 }
234 elseif($mail=="" and $name=="")
235 {
236 $rmessage=_("Error: Both Name and Email address are empty");
237 }
238 elseif($emailok and $nameok)
239 {
240 $uidok=1;
241 $rmessage=_("Name and Email OK.");
242 }
243 elseif(!$emailok and !$nameok)
244 {
245 $rmessage=_("Name and Email both cannot be matched with your account.");
246 }
247 elseif($emailok and $name=="")
248 {
249 $uidok=1;
250 $rmessage=_("The email is OK. The name is empty.");
251 }
252 elseif($nameok and $mail=="")
253 {
254 $uidok=1;
255 $rmessage=_("The name is OK. The email is empty.");
256 }
257 elseif(!$emailok)
258 {
259 $rmessage=_("The email address has not been registered and verified in your account. Please add the email address to your account first.");
260 }
261 elseif(!$nameok)
262 {
263 $rmessage=_("The name in the UID does not match the name in your account. Please verify the name.");
264 }
265
266 else
267 {
268 $rmessage=_("Error");
269 }
270 if($uidok)
271 {
272 $nok++;
273 $resulttable.="<td>$rmessage</td>";
274 $lastvalidemail=$mail;
275 }
276 else
277 {
278 $nerr++;
279 //$ToBeDeleted[]=$i;
280 //echo "Adding UID $i\n";
281 $resulttable.="<td bgcolor='#ffc0c0'>$rmessage</td>";
282 }
283 $resulttable.="</tr>\n";
284
285 if($emailok) $multiple++;
286 }
287 $resulttable.="</table>";
288
289 if($nok==0)
290 {
291 showheader(_("Welcome to CAcert.org"));
292 echo $resulttable;
293
294 echo "<font color='#ff0000'>"._("No valid UIDs found on your key")."</font>";
295 unset($_REQUEST['process']);
296 $id = $oldid;
297 unset($oldid);
298 exit();
299 }
300 elseif($nerr)
301 {
302 $resulttable.=_("The unverified UIDs have been removed, the verified UIDs have been signed.");
303 }
304
305
306 }
307
308
309 if($oldid == "0" && $CSR != "")
310 {
311 write_user_agreement(intval($_SESSION['profile']['id']), "CCA", "certificate creation", "", 1);
312
313 //set variable for comment
314 if(trim($_REQUEST['description']) == ""){
315 $description= "";
316 }else{
317 $description= trim(mysql_real_escape_string(stripslashes($_REQUEST['description'])));
318 }
319
320 $query = "insert into `gpg` set `memid`='".intval($_SESSION['profile']['id'])."',
321 `email`='".mysql_real_escape_string($lastvalidemail)."',
322 `level`='1',
323 `expires`='".mysql_real_escape_string($expires)."',
324 `multiple`='".mysql_real_escape_string($multiple)."',
325 `keyid`='".mysql_real_escape_string($keyid)."',
326 `description`='".mysql_real_escape_string($description)."'";
327 mysql_query($query);
328 $insert_id = mysql_insert_id();
329
330
331 $cwd = '/tmp/gpgspace'.$insert_id;
332 mkdir($cwd,0755);
333
334 $fp = fopen("$cwd/gpg.csr", "w");
335 fputs($fp, clean_gpgcsr($CSR));
336 fclose($fp);
337
338
339 system("gpg --homedir $cwd --import $cwd/gpg.csr");
340
341
342 $cmd_keyid = escapeshellarg($keyid);
343 $gpg = trim(shell_exec("gpg --homedir $cwd --with-colons --fixed-list-mode --list-keys $cmd_keyid 2>&1"));
344 $lines = "";
345 $gpgarr = explode("\n", $gpg);
346 foreach($gpgarr as $line)
347 {
348 //echo "Line[]: $line <br/>\n";
349 if(substr($line, 0, 4) == "uid:")
350 {
351 $name = $comment = "";
352 $bits = explode(":", $line);
353
354 $pos = strpos($bits[9], "(") - 1;
355 $nocomment = 0;
356 if($pos < 0)
357 {
358 $nocomment = 1;
359 $pos = strpos($bits[9], "<") - 1;
360 }
361 if($pos < 0)
362 {
363 $pos = strlen($bits[9]);
364 }
365
366 $name = trim(gpg_hex2bin(trim(substr($bits[9], 0, $pos))));
367 $nameok=verifyName($name);
368 if($nocomment == 0)
369 {
370 $pos += 2;
371 $pos2 = strpos($bits[9], ")");
372 $comm = trim(gpg_hex2bin(trim(substr($bits[9], $pos, $pos2 - $pos))));
373 if($comm != "")
374 $comment[] = $comm;
375 $pos = $pos2 + 3;
376 } else {
377 $pos = strpos($bits[9], "<") + 1;
378 }
379
380 $mail="";
381 if (preg_match("/<([\w.-]*\@[\w.-]*)>/", $bits[9],$match)) {
382 //echo "Found: ".$match[1];
383 $mail = trim(gpg_hex2bin($match[1]));
384 }
385 else
386 {
387 //echo "Not found!\n";
388 }
389
390 $emailok=verifyEmail($mail);
391
392 $uidid=$bits[7];
393
394 if($bits[1]=="r")
395 {
396 $ToBeDeleted[]=$uidid;
397 }
398 elseif($mail=="" and $name=="")
399 {
400 //echo "$uidid will be deleted\n";
401 $ToBeDeleted[]=$uidid;
402 }
403 elseif($emailok and $nameok)
404 {
405 }
406 elseif($emailok and $name=="")
407 {
408 }
409 elseif($nameok and $mail=="")
410 {
411 }
412 elseif(!$emailok and !$nameok)
413 {
414 //echo "$uidid will be deleted\n";
415 $ToBeDeleted[]=$uidid;
416 }
417 elseif(!$emailok)
418 {
419 //echo "$uidid will be deleted\n";
420 $ToBeDeleted[]=$uidid;
421 }
422 elseif(!$nameok)
423 {
424 //echo "$uidid will be deleted\n";
425 $ToBeDeleted[]=$uidid;
426 }
427
428 }
429 }
430
431 if(count($ToBeDeleted)>0)
432 {
433 $descriptorspec = array(
434 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
435 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
436 2 => array("pipe", "w") // stderr is a file to write to
437 );
438
439 $stderr = fopen('php://stderr', 'w');
440
441 //echo "Keyid: $keyid\n";
442
443 $cmd_keyid = escapeshellarg($keyid);
444 $process = proc_open("/usr/bin/gpg --homedir $cwd --no-tty --command-fd 0 --status-fd 1 --logger-fd 2 --edit-key $cmd_keyid", $descriptorspec, $pipes);
445
446 //echo "Process: $process\n";
447 //fputs($stderr,"Process: $process\n");
448
449 if (is_resource($process)) {
450 //echo("it is a resource\n");
451 // $pipes now looks like this:
452 // 0 => writeable handle connected to child stdin
453 // 1 => readable handle connected to child stdout
454 // Any error output will be appended to /tmp/error-output.txt
455 while (!feof($pipes[1]))
456 {
457 $buffer = fgets($pipes[1], 4096);
458 //echo $buffer;
459
460 if($buffer == "[GNUPG:] GET_BOOL keyedit.sign_all.okay\n")
461 {
462 fputs($pipes[0],"yes\n");
463 }
464 elseif($buffer == "[GNUPG:] GOT_IT\n")
465 {
466 }
467 elseif(ereg("^\[GNUPG:\] GET_BOOL keyedit\.remove\.uid\.okay\s*",$buffer))
468 {
469 fputs($pipes[0],"yes\n");
470 }
471 elseif(ereg("^\[GNUPG:\] GET_LINE keyedit\.prompt\s*",$buffer))
472 {
473 if(count($ToBeDeleted)>0)
474 {
475 $delthisuid=array_pop($ToBeDeleted);
476 //echo "Deleting an UID $delthisuid\n";
477 fputs($pipes[0],"uid ".$delthisuid."\n");
478 }
479 else
480 {
481 //echo "Saving\n";
482 fputs($pipes[0],$state?"save\n":"deluid\n");
483 $state++;
484 }
485 }
486 elseif($buffer == "[GNUPG:] GOOD_PASSPHRASE\n")
487 {
488 }
489 elseif(ereg("^\[GNUPG:\] KEYEXPIRED ",$buffer))
490 {
491 echo "Key expired!\n";
492 exit;
493 }
494 elseif($buffer == "")
495 {
496 //echo "Empty!\n";
497 }
498 else
499 {
500 echo "ERROR: UNKNOWN $buffer\n";
501 }
502
503
504 }
505 //echo "Fertig\n";
506 fclose($pipes[0]);
507
508 //echo stream_get_contents($pipes[1]);
509 fclose($pipes[1]);
510
511 // It is important that you close any pipes before calling
512 // proc_close in order to avoid a deadlock
513 $return_value = proc_close($process);
514
515 //echo "command returned $return_value\n";
516 }
517 else
518 {
519 echo "Keine ressource!\n";
520 }
521
522
523 }
524
525
526 $csrname=generatecertpath("csr","gpg",$insert_id);
527 $cmd_keyid = escapeshellarg($keyid);
528 $do=shell_exec("gpg --homedir $cwd --batch --export-options export-minimal --export $cmd_keyid >$csrname");
529
530 mysql_query("update `gpg` set `csr`='$csrname' where `id`='$insert_id'");
531 waitForResult('gpg', $insert_id);
532
533 showheader(_("Welcome to CAcert.org"));
534 echo $resulttable;
535 $query = "select * from `gpg` where `id`='$insert_id' and `crt`!=''";
536 $res = mysql_query($query);
537 if(mysql_num_rows($res) <= 0)
538 {
539 echo _("Your certificate request has failed to be processed correctly, please try submitting it again.")."<br>\n";
540 echo _("If this is a re-occuring problem, please send a copy of the key you are trying to signed to support@cacert.org. Thank you.");
541 } else {
542 echo "<pre>";
543 readfile(generatecertpath("crt","gpg",$insert_id));
544 echo "</pre>";
545 }
546
547 showfooter();
548 exit;
549 }
550
551 if($oldid == 2 && array_key_exists('change',$_REQUEST) && $_REQUEST['change'] != "")
552 {
553 showheader(_("My CAcert.org Account!"));
554 foreach($_REQUEST as $id => $val)
555 {
556 if(substr($id,0,14)=="check_comment_")
557 {
558 $cid = intval(substr($id,14));
559 $comment=trim(mysql_real_escape_string(stripslashes($_REQUEST['comment_'.$cid])));
560 mysql_query("update `gpg` set `description`='$comment' where `id`='$cid' and `memid`='".$_SESSION['profile']['id']."'");
561 }
562 }
563 echo(_("Certificate settings have been changed.")."<br/>\n");
564 showfooter();
565 exit;
566 }
567
568 $id = intval($id);
569
570 showheader(_("Welcome to CAcert.org"));
571 includeit($id, "gpg");
572 showfooter();
573 ?>