|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace MadWizard\WebAuthn\Crypto; |
|
4
|
|
|
|
|
5
|
|
|
class Der |
|
6
|
|
|
{ |
|
7
|
19 |
|
private static function length(int $len): string |
|
8
|
|
|
{ |
|
9
|
19 |
|
if ($len < 128) { |
|
10
|
19 |
|
return \chr($len); |
|
11
|
|
|
} |
|
12
|
|
|
|
|
13
|
6 |
|
$lenBytes = ''; |
|
14
|
6 |
|
while ($len > 0) { |
|
15
|
6 |
|
$lenBytes = \chr($len % 256) . $lenBytes; |
|
16
|
6 |
|
$len = \intdiv($len, 256); |
|
17
|
|
|
} |
|
18
|
6 |
|
return \chr(0x80 | \strlen($lenBytes)) . $lenBytes; |
|
19
|
|
|
} |
|
20
|
|
|
|
|
21
|
16 |
|
public static function sequence(string $contents): string |
|
22
|
|
|
{ |
|
23
|
16 |
|
return "\x30" . self::length(\strlen($contents)) . $contents; |
|
24
|
|
|
} |
|
25
|
|
|
|
|
26
|
16 |
|
public static function oid(string $encoded): string |
|
27
|
|
|
{ |
|
28
|
16 |
|
return "\x06" . self::length(\strlen($encoded)) . $encoded; |
|
29
|
|
|
} |
|
30
|
|
|
|
|
31
|
8 |
|
public static function unsignedInteger(string $bytes): string |
|
32
|
|
|
{ |
|
33
|
8 |
|
$len = \strlen($bytes); |
|
34
|
|
|
|
|
35
|
|
|
// Remove leading zero bytes |
|
36
|
8 |
|
for ($i = 0; $i < ($len - 1); $i++) { |
|
37
|
8 |
|
if (\ord($bytes[$i]) !== 0) { |
|
38
|
8 |
|
break; |
|
39
|
|
|
} |
|
40
|
|
|
} |
|
41
|
8 |
|
if ($i !== 0) { |
|
42
|
1 |
|
$bytes = \substr($bytes, $i); |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
|
|
// If most significant bit is set, prefix with another zero to prevent it being seen as negative number |
|
46
|
8 |
|
if ((\ord($bytes[0]) & 0x80) !== 0) { |
|
47
|
8 |
|
$bytes = "\x00" . $bytes; |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
8 |
|
return "\x02" . self::length(\strlen($bytes)) . $bytes; |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
16 |
|
public static function bitString(string $bytes): string |
|
54
|
|
|
{ |
|
55
|
16 |
|
$len = \strlen($bytes) + 1; |
|
56
|
|
|
|
|
57
|
16 |
|
return "\x03" . self::length($len) . "\x00" . $bytes; |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
public static function octetString(string $bytes): string |
|
61
|
|
|
{ |
|
62
|
|
|
$len = \strlen($bytes); |
|
63
|
|
|
|
|
64
|
|
|
return "\x04" . self::length($len) . $bytes; |
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
public static function contextTag(int $tag, bool $constructed, string $content): string |
|
68
|
|
|
{ |
|
69
|
|
|
return \chr(($tag & 0x1F) | // Context specific tag number |
|
70
|
|
|
(1 << 7) | // Context-specific flag |
|
71
|
|
|
($constructed ? (1 << 5) : 0)) . |
|
72
|
|
|
self::length(\strlen($content)) . |
|
73
|
|
|
$content; |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
6 |
|
public static function nullValue(): string |
|
77
|
|
|
{ |
|
78
|
6 |
|
return "\x05\x00"; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
14 |
|
public static function pem(string $type, string $der): string |
|
82
|
|
|
{ |
|
83
|
14 |
|
return sprintf("-----BEGIN %s-----\n", strtoupper($type)) . |
|
84
|
14 |
|
chunk_split(base64_encode($der), 64, "\n") . |
|
85
|
14 |
|
sprintf("-----END %s-----\n", strtoupper($type)); |
|
86
|
|
|
} |
|
87
|
|
|
} |
|
88
|
|
|
|