blob: c04d63e2474547725a897caea47c97ee1854602b [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2/**
3 * Copyright (c) 2014 Yubico AB
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * This is a simple example using PDO and a sqlite database for storing
33 * registrations. It supports multiple registrations associated with each user.
34 */
35
36require_once('../../src/u2flib_server/U2F.php');
37
38$dbfile = '/var/tmp/u2f-pdo.sqlite';
39
40$pdo = new PDO("sqlite:$dbfile");
41$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
42$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
43
44$pdo->exec("create table if not exists users (id integer primary key, name varchar(255))");
45$pdo->exec("create table if not exists registrations (id integer primary key, user_id integer, keyHandle varchar(255), publicKey varchar(255), certificate text, counter integer)");
46
47$scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
48$u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
49
50session_start();
51
52function createAndGetUser($name) {
53 global $pdo;
54 $sel = $pdo->prepare("select * from users where name = ?");
55 $sel->execute(array($name));
56 $user = $sel->fetch();
57 if(!$user) {
58 $ins = $pdo->prepare("insert into users (name) values(?)");
59 $ins->execute(array($name));
60 $sel->execute(array($name));
61 $user = $sel->fetch();
62 }
63 return $user;
64}
65
66function getRegs($user_id) {
67 global $pdo;
68 $sel = $pdo->prepare("select * from registrations where user_id = ?");
69 $sel->execute(array($user_id));
70 return $sel->fetchAll();
71}
72
73function addReg($user_id, $reg) {
74 global $pdo;
75 $ins = $pdo->prepare("insert into registrations (user_id, keyHandle, publicKey, certificate, counter) values (?, ?, ?, ?, ?)");
76 $ins->execute(array($user_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
77}
78
79function updateReg($reg) {
80 global $pdo;
81 $upd = $pdo->prepare("update registrations set counter = ? where id = ?");
82 $upd->execute(array($reg->counter, $reg->id));
83}
84
85?>
86
87<html>
88<head>
89 <title>PHP U2F example</title>
90
91 <script src="../assets/u2f-api.js"></script>
92
93 <script>
94 <?php
95
96 if($_SERVER['REQUEST_METHOD'] === 'POST') {
97 if(!$_POST['username']) {
98 echo "alert('no username provided!');";
99 } else if(!isset($_POST['action']) && !isset($_POST['register2']) && !isset($_POST['authenticate2'])) {
100 echo "alert('no action provided!');";
101 } else {
102 $user = createAndGetUser($_POST['username']);
103
104 if(isset($_POST['action'])) {
105 switch($_POST['action']):
106 case 'register':
107 try {
108 $data = $u2f->getRegisterData(getRegs($user->id));
109
110 list($req,$sigs) = $data;
111 $_SESSION['regReq'] = json_encode($req);
112 echo "var req = " . json_encode($req) . ";";
113 echo "var sigs = " . json_encode($sigs) . ";";
114 echo "var username = '" . $user->name . "';";
115 ?>
116 setTimeout(function() {
117 console.log("Register: ", req);
118 u2f.register([req], sigs, function(data) {
119 var form = document.getElementById('form');
120 var reg = document.getElementById('register2');
121 var user = document.getElementById('username');
122 console.log("Register callback", data);
123 if(data.errorCode && errorCode != 0) {
124 alert("registration failed with errror: " + data.errorCode);
125 return;
126 }
127 reg.value = JSON.stringify(data);
128 user.value = username;
129 form.submit();
130 });
131 }, 1000);
132 <?php
133 } catch( Exception $e ) {
134 echo "alert('error: " . $e->getMessage() . "');";
135 }
136
137 break;
138
139 case 'authenticate':
140 try {
141 $reqs = json_encode($u2f->getAuthenticateData(getRegs($user->id)));
142
143 $_SESSION['authReq'] = $reqs;
144 echo "var req = $reqs;";
145 echo "var username = '" . $user->name . "';";
146 ?>
147 setTimeout(function() {
148 console.log("sign: ", req);
149 u2f.sign(req, function(data) {
150 var form = document.getElementById('form');
151 var auth = document.getElementById('authenticate2');
152 var user = document.getElementById('username');
153 console.log("Authenticate callback", data);
154 auth.value=JSON.stringify(data);
155 user.value = username;
156 form.submit();
157 });
158 }, 1000);
159 <?php
160 } catch( Exception $e ) {
161 echo "alert('error: " . $e->getMessage() . "');";
162 }
163
164 break;
165
166 endswitch;
167 } else if($_POST['register2']) {
168 try {
169 $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($_POST['register2']));
170 addReg($user->id, $reg);
171 } catch( Exception $e ) {
172 echo "alert('error: " . $e->getMessage() . "');";
173 } finally {
174 $_SESSION['regReq'] = null;
175 }
176 } else if($_POST['authenticate2']) {
177 try {
178 $reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), getRegs($user->id), json_decode($_POST['authenticate2']));
179 updateReg($reg);
180 echo "alert('success: " . $reg->counter . "');";
181 } catch( Exception $e ) {
182 echo "alert('error: " . $e->getMessage() . "');";
183 } finally {
184 $_SESSION['authReq'] = null;
185 }
186 }
187 }
188 }
189 ?>
190 </script>
191</head>
192<body>
193
194<form method="POST" id="form">
195 username: <input name="username" id="username"/><br/>
196 register: <input value="register" name="action" type="radio"/><br/>
197 authenticate: <input value="authenticate" name="action" type="radio"/><br/>
198 <input type="hidden" name="register2" id="register2"/>
199 <input type="hidden" name="authenticate2" id="authenticate2"/>
200 <button type="submit">Submit!</button>
201</form>
202
203</body>
204</html>