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
|
|
|
|