1<?php
2
3/**
4 * Nonce-related functionality.
5 *
6 * @package OpenID
7 */
8
9/**
10 * Need CryptUtil to generate random strings.
11 */
12require_once 'Auth/OpenID/CryptUtil.php';
13
14/**
15 * This is the characters that the nonces are made from.
16 */
17define('Auth_OpenID_Nonce_CHRS',"abcdefghijklmnopqrstuvwxyz" .
18       "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
19
20// Keep nonces for five hours (allow five hours for the combination of
21// request time and clock skew). This is probably way more than is
22// necessary, but there is not much overhead in storing nonces.
23global $Auth_OpenID_SKEW;
24$Auth_OpenID_SKEW = 60 * 60 * 5;
25
26define('Auth_OpenID_Nonce_REGEX',
27       '/(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z(.*)/');
28
29define('Auth_OpenID_Nonce_TIME_FMT',
30       '%Y-%m-%dT%H:%M:%SZ');
31
32function Auth_OpenID_splitNonce($nonce_string)
33{
34    // Extract a timestamp from the given nonce string
35    $result = preg_match(Auth_OpenID_Nonce_REGEX, $nonce_string, $matches);
36    if ($result != 1 || count($matches) != 8) {
37        return null;
38    }
39
40    list($unused,
41         $tm_year,
42         $tm_mon,
43         $tm_mday,
44         $tm_hour,
45         $tm_min,
46         $tm_sec,
47         $uniquifier) = $matches;
48
49    $timestamp =
50        @gmmktime($tm_hour, $tm_min, $tm_sec, $tm_mon, $tm_mday, $tm_year);
51
52    if ($timestamp === false || $timestamp < 0) {
53        return null;
54    }
55
56    return array($timestamp, $uniquifier);
57}
58
59function Auth_OpenID_checkTimestamp($nonce_string,
60                                    $allowed_skew = null,
61                                    $now = null)
62{
63    // Is the timestamp that is part of the specified nonce string
64    // within the allowed clock-skew of the current time?
65    global $Auth_OpenID_SKEW;
66
67    if ($allowed_skew === null) {
68        $allowed_skew = $Auth_OpenID_SKEW;
69    }
70
71    $parts = Auth_OpenID_splitNonce($nonce_string);
72    if ($parts == null) {
73        return false;
74    }
75
76    if ($now === null) {
77        $now = time();
78    }
79
80    $stamp = $parts[0];
81
82    // Time after which we should not use the nonce
83    $past = $now - $allowed_skew;
84
85    // Time that is too far in the future for us to allow
86    $future = $now + $allowed_skew;
87
88    // the stamp is not too far in the future and is not too far
89    // in the past
90    return (($past <= $stamp) && ($stamp <= $future));
91}
92
93function Auth_OpenID_mkNonce($when = null)
94{
95    // Generate a nonce with the current timestamp
96    $salt = Auth_OpenID_CryptUtil::randomString(
97        6, Auth_OpenID_Nonce_CHRS);
98    if ($when === null) {
99        // It's safe to call time() with no arguments; it returns a
100        // GMT unix timestamp on PHP 4 and PHP 5.  gmmktime() with no
101        // args returns a local unix timestamp on PHP 4, so don't use
102        // that.
103        $when = time();
104    }
105    $time_str = gmstrftime(Auth_OpenID_Nonce_TIME_FMT, $when);
106    return $time_str . $salt;
107}
108
109