diff options
author | Gordon GECOS <u@adam> | 2023-11-24 23:01:55 -0500 |
---|---|---|
committer | Gordon GECOS <u@adam> | 2023-11-25 11:12:26 -0500 |
commit | 53927610e50170cc0d7ead7b17e6c933f88f9568 (patch) | |
tree | 434b1c6a1036a980738c6c2675a8d780976911c2 | |
parent | ca48d24bf83a7ce68f3f93449012da40b61015e5 (diff) |
base64
-rw-r--r-- | src/base64.pk | 216 | ||||
-rwxr-xr-x | src/ssh-keysign.pk | 69 |
2 files changed, 247 insertions, 38 deletions
diff --git a/src/base64.pk b/src/base64.pk new file mode 100644 index 0000000..b35718d --- /dev/null +++ b/src/base64.pk | |||
@@ -0,0 +1,216 @@ | |||
1 | /* base64.pk - base64 ASCII encoding for GNU poke. */ | ||
2 | |||
3 | /* This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 3 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | /* Copyright (C) 2023 Jose E. Marchesi. | ||
18 | * | ||
19 | * Poke version of the Internet Software Consortium C implementation | ||
20 | * of base64, which is: | ||
21 | * | ||
22 | * Copyright (c) 1996-1999 by Internet Software Consortium. | ||
23 | * | ||
24 | * Permission to use, copy, modify, and distribute this software for any | ||
25 | * purpose with or without fee is hereby granted, provided that the above | ||
26 | * copyright notice and this permission notice appear in all copies. | ||
27 | * | ||
28 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | ||
29 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | ||
30 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | ||
31 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | ||
32 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | ||
33 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | ||
34 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | ||
35 | * SOFTWARE. */ | ||
36 | |||
37 | /* The base64 encoding is specified by | ||
38 | https://datatracker.ietf.org/doc/html/rfc4648 */ | ||
39 | |||
40 | var base64_chars | ||
41 | = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
42 | |||
43 | fun base64_encode = (uint<8>[] src) string: | ||
44 | { | ||
45 | var srclength = src'length; | ||
46 | var targsize = (src'length /^ 3) * 4; | ||
47 | var target = uint<8>[targsize](); | ||
48 | var input = uint<8>[3](); | ||
49 | var output = uint<8>[4](); | ||
50 | var s = 0UL; | ||
51 | var datalength = 0UL; | ||
52 | |||
53 | while (srclength > 2) | ||
54 | { | ||
55 | input[0] = src[s++]; | ||
56 | input[1] = src[s++]; | ||
57 | input[2] = src[s++]; | ||
58 | srclength -= 3; | ||
59 | |||
60 | output[0] = input[0] .>> 2; | ||
61 | output[1] = ((input[0] & 0x03) <<. 4) + (input[1] .>> 4); | ||
62 | output[2] = ((input[1] & 0x0f) <<. 2) + (input[2] .>> 6); | ||
63 | output[3] = input[2] & 0x3f; | ||
64 | assert (output[0] < 64); | ||
65 | assert (output[1] < 64); | ||
66 | assert (output[2] < 64); | ||
67 | assert (output[3] < 64); | ||
68 | |||
69 | target[datalength++] = base64_chars[output[0]]; | ||
70 | target[datalength++] = base64_chars[output[1]]; | ||
71 | target[datalength++] = base64_chars[output[2]]; | ||
72 | target[datalength++] = base64_chars[output[3]]; | ||
73 | } | ||
74 | |||
75 | /* Do now the padding. */ | ||
76 | if (srclength != 0) | ||
77 | { | ||
78 | input[2] = '\0'; | ||
79 | input[1] = '\0'; | ||
80 | input[0] = '\0'; | ||
81 | |||
82 | for (var i = 0; i < srclength; i++) | ||
83 | input[i] = src[s++]; | ||
84 | |||
85 | output[0] = input[0] .>> 2; | ||
86 | output[1] = ((input[0] & 0x03) <<. 4) + (input[1] .>> 4); | ||
87 | output[2] = ((input[1] & 0x0f) <<. 2) + (input[2] .>> 6); | ||
88 | assert (output[0] < 64); | ||
89 | assert (output[1] < 64); | ||
90 | assert (output[2] < 64); | ||
91 | |||
92 | target[datalength++] = base64_chars[output[0]]; | ||
93 | target[datalength++] = base64_chars[output[1]]; | ||
94 | if (srclength == 1) | ||
95 | target[datalength++] = '='; | ||
96 | else | ||
97 | target[datalength++] = base64_chars[output[2]]; | ||
98 | target[datalength++] = '='; | ||
99 | } | ||
100 | |||
101 | return catos (target); | ||
102 | } | ||
103 | |||
104 | fun base64_decode = (string src) uint<8>[]: | ||
105 | { | ||
106 | fun invalid_input = (string cause, int<32> position) void: | ||
107 | { | ||
108 | raise Exception { code = EC_inval, | ||
109 | name = "invalid argument", | ||
110 | msg = cause + format (" at position %i32d", position) }; | ||
111 | } | ||
112 | |||
113 | var srclength = src'length; | ||
114 | var targsize = (rtrim (src, "=")'length /^ 4) * 3; | ||
115 | var target = uint<8>[targsize+1](); | ||
116 | |||
117 | var state = 0; | ||
118 | var tarindex = 0; | ||
119 | var ch = 0UB; | ||
120 | var s = 0UL; | ||
121 | |||
122 | while (s < srclength) | ||
123 | { | ||
124 | ch = src[s++]; | ||
125 | |||
126 | if (ch == ' ') | ||
127 | continue; | ||
128 | |||
129 | if (ch == '=') | ||
130 | { | ||
131 | s--; | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | var pos = strchr (base64_chars, ch); | ||
136 | |||
137 | if (pos == base64_chars'length) /* A non-base64 character. */ | ||
138 | invalid_input ("non-base64 character passed to base_64_decode", s - 1); | ||
139 | |||
140 | if (state == 0) | ||
141 | { | ||
142 | assert (tarindex < targsize); | ||
143 | target[tarindex] = pos <<. 2; | ||
144 | state = 1; | ||
145 | } | ||
146 | else if (state == 1) | ||
147 | { | ||
148 | assert (tarindex + 1 < targsize); | ||
149 | target[tarindex] |= pos .>> 4; | ||
150 | target[tarindex + 1] = (pos & 0x0f) <<. 4; | ||
151 | tarindex += 1; | ||
152 | state = 2; | ||
153 | } | ||
154 | else if (state == 2) | ||
155 | { | ||
156 | assert (tarindex + 1 < targsize); | ||
157 | target[tarindex] |= pos .>> 2; | ||
158 | target[tarindex + 1] = (pos & 0x03) <<. 6; | ||
159 | tarindex += 1; | ||
160 | state = 3; | ||
161 | } | ||
162 | else if (state == 3) | ||
163 | { | ||
164 | assert (tarindex < targsize); | ||
165 | target[tarindex] |= pos; | ||
166 | tarindex++; | ||
167 | state = 0; | ||
168 | } | ||
169 | else | ||
170 | /* Unreachable. */ | ||
171 | assert (0); | ||
172 | } | ||
173 | |||
174 | /* We are done with the base-64 chars. Let's see if we ended on a | ||
175 | byte boundary, and/or with erroneous trailing characters. */ | ||
176 | if (ch == '=') | ||
177 | { | ||
178 | ch = src[s++]; | ||
179 | if (state == 0 || state == 1) | ||
180 | { | ||
181 | invalid_input ("invalid `=' in string passed to base64_decode", | ||
182 | s - 1); | ||
183 | } | ||
184 | else if (state == 2 || state == 3) | ||
185 | { | ||
186 | if (state == 2) | ||
187 | { | ||
188 | /* Skip any number of spaces. */ | ||
189 | while (s < srclength) | ||
190 | { | ||
191 | ch = src[s++]; | ||
192 | if (ch != ' ') | ||
193 | break; | ||
194 | } | ||
195 | /* Make sure there is another trailing = sign. */ | ||
196 | if (ch != '=') | ||
197 | invalid_input ("expected `=' in string passed to base64_decode", | ||
198 | s - 1); | ||
199 | } | ||
200 | |||
201 | /* State 2 and 3. */ | ||
202 | while (s < srclength) | ||
203 | { | ||
204 | ch = src[s++]; | ||
205 | if (ch != ' ') | ||
206 | invalid_input ("expected whitespace in string passed to base64_decode", | ||
207 | s - 1); | ||
208 | } | ||
209 | |||
210 | if (target[tarindex] != 0) | ||
211 | raise E_inval; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | return target[:tarindex]; | ||
216 | } | ||
diff --git a/src/ssh-keysign.pk b/src/ssh-keysign.pk index 1c17110..40ccd97 100755 --- a/src/ssh-keysign.pk +++ b/src/ssh-keysign.pk | |||
@@ -1,70 +1,64 @@ | |||
1 | #!/usr/bin/poke -L | 1 | #!/usr/bin/poke -L |
2 | !# | 2 | !# |
3 | 3 | ||
4 | load "src/base64.pk"; | ||
5 | |||
6 | fun encode = (any v) string: | ||
7 | { | ||
8 | return base64_encode (uint<8>[v'size] @ v'ios : v'offset); | ||
9 | } | ||
10 | |||
4 | type SSH_String = | 11 | type SSH_String = |
5 | struct | 12 | struct |
6 | { | 13 | { |
7 | uint<32> size; | 14 | uint<32> size; |
8 | byte[size] data; | 15 | byte[size] bytes; |
9 | }; | 16 | }; |
10 | 17 | ||
11 | type SSH_Publickey = | 18 | type SSH_Publickey_Blob = |
12 | struct | 19 | struct |
13 | { | 20 | { |
14 | SSH_String key_type : catos(key_type.data) == "ssh-ed25519"; | 21 | SSH_String key_type : catos (key_type.bytes) == "ssh-ed25519"; |
15 | SSH_String key_data : key_data.size == 32; | 22 | SSH_String key_data : key_data.size == 32; |
16 | }; | 23 | }; |
17 | 24 | ||
18 | type SSH_Signature = | 25 | type SSH_Signature_Blob = |
19 | struct | 26 | struct |
20 | { | 27 | { |
21 | SSH_String sig_type : catos(sig_type.data) == "ssh-ed25519"; | 28 | SSH_String sig_type : catos (sig_type.bytes) == "ssh-ed25519"; |
22 | SSH_String sig_data; | 29 | SSH_String sig_data : sig_data.size == 64; |
23 | }; | 30 | }; |
24 | 31 | ||
25 | type SSH_Signature_String = | 32 | type SSH_Signature_String = |
26 | struct | 33 | struct |
27 | { | 34 | { |
28 | uint<32> size; | 35 | uint<32> size; |
29 | union { | 36 | SSH_Signature_Blob blob; |
30 | SSH_Signature sig; | ||
31 | byte[size] raw; | ||
32 | } data; | ||
33 | }; | 37 | }; |
34 | 38 | ||
35 | type SSH_Publickey_String = | 39 | type SSH_Publickey_String = |
36 | struct | 40 | struct |
37 | { | 41 | { |
38 | uint<32> size; | 42 | uint<32> size; |
39 | union { | 43 | SSH_Publickey_Blob blob; |
40 | SSH_Publickey key; | ||
41 | byte[size] raw; | ||
42 | } data; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | type SSH_Signature = | 46 | type SSH_Signature = |
46 | struct | 47 | struct |
47 | { | 48 | { |
48 | uint<32> size; | 49 | byte[6] MAGIC_PREAMBLE : catos (MAGIC_PREAMBLE) == "SSHSIG"; |
49 | byte[size] data; | ||
50 | }; | ||
51 | |||
52 | type SSH_Signature_Blob = | ||
53 | struct | ||
54 | { | ||
55 | byte[6] MAGIC_PREAMBLE : catos(MAGIC_PREAMBLE) == "SSHSIG"; | ||
56 | uint<32> SIG_VERSION : SIG_VERSION == 1; | 50 | uint<32> SIG_VERSION : SIG_VERSION == 1; |
57 | SSH_Publickey_String publickey; | 51 | SSH_Publickey_String publickey; |
58 | SSH_String namespace; | 52 | SSH_String namespace; |
59 | SSH_String reserved; | 53 | SSH_String reserved; |
60 | SSH_String hash_algorithm; | 54 | SSH_String hash_algorithm : catos (hash_algorithm.bytes) == "sha512"; |
61 | SSH_Signature_String signature; | 55 | SSH_Signature_String signature; |
62 | }; | 56 | }; |
63 | 57 | ||
64 | if (!(argv'length in [1])) | 58 | if (!(argv'length in [1])) |
65 | { | 59 | { |
66 | print("Usage: ssh-keysign.pk FILE\n"); | 60 | print ("Usage: ssh-keysign.pk FILE\n"); |
67 | exit(1); | 61 | exit (1); |
68 | } | 62 | } |
69 | 63 | ||
70 | var file_name = argv[0]; | 64 | var file_name = argv[0]; |
@@ -72,19 +66,18 @@ var file_name = argv[0]; | |||
72 | try | 66 | try |
73 | { | 67 | { |
74 | var fd = open (file_name, IOS_M_RDONLY); | 68 | var fd = open (file_name, IOS_M_RDONLY); |
75 | var sig = SSH_Signature_Blob @ fd : 0#B; | 69 | var sig = SSH_Signature @ fd : 0#B; |
76 | printf("%s: %s (%i32d bytes)\n", "publickey", | 70 | printf ("%s: %s %s (raw: %s)\n", "publickey", |
77 | catos(sig.publickey.data.key.key_type.data), | 71 | catos (sig.publickey.blob.key_type.bytes), |
78 | sig.publickey.data.key.key_data.size); | 72 | encode (sig.publickey.blob), |
79 | printf("%s: %s\n", "namespace", | 73 | encode (sig.publickey.blob.key_data.bytes)); |
80 | catos(sig.namespace.data)); | 74 | printf ("%s: %v\n", "namespace", catos (sig.namespace.bytes)); |
81 | printf("%s: <%i32d bytes>\n", "reserved", | 75 | printf ("%s: <%i32d bytes>\n", "reserved", sig.reserved.size); |
82 | sig.reserved.size); | 76 | printf ("%s: %s\n", "hash_algorithm", catos (sig.hash_algorithm.bytes)); |
83 | printf("%s: %s\n", "hash_algorithm", | 77 | printf ("%s: %s %s (raw: %s)\n", "signature", |
84 | catos(sig.hash_algorithm.data)); | 78 | catos (sig.signature.blob.sig_type.bytes), |
85 | printf("%s: %s (%i32d bytes)\n", "signature", | 79 | encode (sig.signature.blob), |
86 | catos(sig.signature.data.sig.sig_type.data), | 80 | encode (sig.signature.blob.sig_data.bytes)); |
87 | sig.signature.data.sig.sig_data.size); | ||
88 | close (fd); | 81 | close (fd); |
89 | } | 82 | } |
90 | catch (Exception e) | 83 | catch (Exception e) |