1 #define _POSIX_C_SOURCE 200112L
22 #define LINEFEED_LEN (sizeof(char))
23 #define NULLTERM_LEN (sizeof(char))
25 static const char keys_field_generated
[] = "---";
26 static const char keys_field_hostname
[] = "hostname: ";
27 static const char keys_field_publickey
[] = "hs_ed25519_public_key: ";
28 static const char keys_field_secretkey
[] = "hs_ed25519_secret_key: ";
29 static const char keys_field_time
[] = "time: ";
31 #define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
32 #define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
33 #define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
34 #define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
35 #define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
37 #define B64_PUBKEY_LEN (BASE64_TO_LEN(FORMATTED_PUBLIC_LEN))
38 #define B64_SECKEY_LEN (BASE64_TO_LEN(FORMATTED_SECRET_LEN))
39 #define B64_RAW_PUBKEY_LEN (BASE64_TO_LEN(PUBLIC_LEN))
40 #define B64_RAW_SECKEY_LEN (BASE64_TO_LEN(SECRET_LEN))
41 #define TIME_LEN 21 // strlen("2018-07-04 21:31:20 Z")
44 KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN + \
45 KEYS_FIELD_HOSTNAME_LEN + ONION_LEN + LINEFEED_LEN + \
46 KEYS_FIELD_PUBLICKEY_LEN + B64_PUBKEY_LEN + LINEFEED_LEN + \
47 KEYS_FIELD_SECRETKEY_LEN + B64_SECKEY_LEN + LINEFEED_LEN + \
48 KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
50 #define RAW_KEYS_LEN (KEYS_LEN \
51 - B64_PUBKEY_LEN + B64_RAW_PUBKEY_LEN \
52 - B64_SECKEY_LEN + B64_RAW_SECKEY_LEN)
54 static pthread_mutex_t tminfo_mutex
;
56 void yamlout_init(void)
58 pthread_mutex_init(&tminfo_mutex
,0);
61 void yamlout_clean(void)
63 pthread_mutex_destroy(&tminfo_mutex
);
66 #define BUF_APPEND(buf,offset,src,srclen) \
68 memcpy(&buf[offset],(src),(srclen)); \
71 #define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
72 #define BUF_APPEND_CHAR(buf,offset,c) buf[offset++] = (c)
74 void yamlout_writekeys(
75 const char *hostname
,const u8
*publickey
,const u8
*secretkey
,int rawkeys
)
77 char keysbuf
[KEYS_LEN
];
78 char pubkeybuf
[B64_PUBKEY_LEN
+ NULLTERM_LEN
];
79 char seckeybuf
[B64_SECKEY_LEN
+ NULLTERM_LEN
];
80 char timebuf
[TIME_LEN
+ NULLTERM_LEN
];
84 BUF_APPEND(keysbuf
,offset
,keys_field_generated
,KEYS_FIELD_GENERATED_LEN
);
85 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
88 BUF_APPEND(keysbuf
,offset
,keys_field_hostname
,KEYS_FIELD_HOSTNAME_LEN
);
89 BUF_APPEND(keysbuf
,offset
,hostname
,ONION_LEN
);
90 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
93 BUF_APPEND(keysbuf
,offset
,keys_field_publickey
,KEYS_FIELD_PUBLICKEY_LEN
);
96 base64_to(pubkeybuf
,publickey
,FORMATTED_PUBLIC_LEN
);
98 base64_to(pubkeybuf
,&publickey
[PKPREFIX_SIZE
],PUBLIC_LEN
);
100 BUF_APPEND_CSTR(keysbuf
,offset
,pubkeybuf
);
101 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
104 BUF_APPEND(keysbuf
,offset
,keys_field_secretkey
,KEYS_FIELD_SECRETKEY_LEN
);
107 base64_to(seckeybuf
,secretkey
,FORMATTED_SECRET_LEN
);
109 base64_to(seckeybuf
,&secretkey
[SKPREFIX_SIZE
],SECRET_LEN
);
111 BUF_APPEND_CSTR(keysbuf
,offset
,seckeybuf
);
112 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
115 BUF_APPEND(keysbuf
,offset
,keys_field_time
,KEYS_FIELD_TIME_LEN
);
121 pthread_mutex_lock(&tminfo_mutex
);
122 tm_info
= gmtime(&currtime
);
123 strftime(timebuf
,sizeof(timebuf
),"%Y-%m-%d %H:%M:%S Z",tm_info
);
124 pthread_mutex_unlock(&tminfo_mutex
);
126 BUF_APPEND(keysbuf
,offset
,timebuf
,TIME_LEN
);
127 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
130 assert(offset
== (!rawkeys
? KEYS_LEN
: RAW_KEYS_LEN
));
133 pthread_mutex_lock(&fout_mutex
);
134 fwrite(keysbuf
,offset
,1,fout
);
136 pthread_mutex_unlock(&fout_mutex
);
139 #undef BUF_APPEND_CHAR
140 #undef BUF_APPEND_CSTR
143 // pseudo YAML parser
144 int yamlin_parseandcreate(
145 FILE *fin
,char *sname
,const char *onehostname
,int rawkeys
)
149 u8 pubbuf
[BASE64_DATA_ALIGN(FORMATTED_PUBLIC_LEN
)];
150 u8 secbuf
[BASE64_DATA_ALIGN(FORMATTED_SECRET_LEN
)];
151 int hashost
= 0,haspub
= 0,hassec
= 0,skipthis
= 0;
152 enum keytype
{ HOST
, PUB
, SEC
} keyt
;
155 memcpy(pubbuf
,pkprefix
,PKPREFIX_SIZE
);
156 memcpy(secbuf
,skprefix
,SKPREFIX_SIZE
);
159 while (!feof(fin
) && !ferror(fin
)) {
160 if (!fgets(line
,sizeof(line
),fin
))
165 // trim whitespace from the end
166 while (len
!= 0 && (line
[len
-1] == ' ' || line
[len
-1] == '\n' || line
[len
-1] == '\r'))
173 if (len
>= 3 && line
[0] == '-' && line
[1] == '-' && line
[2] == '-') {
174 // end of document / start of new document indicator
175 if (!skipthis
&& (hashost
|| haspub
|| hassec
)) {
176 fprintf(stderr
,"ERROR: incomplete record\n");
179 hashost
= haspub
= hassec
= skipthis
= 0;
188 while (len
!= 0 && *start
== ' ') {
194 for (;*p
!= '\0';++p
) {
201 fprintf(stderr
,"ERROR: invalid syntax\n");
202 return 1; // XXX could continue too there but eh
206 if (!strcmp(start
,"hostname"))
208 else if (!strcmp(start
,"hs_ed25519_public_key"))
210 else if (!strcmp(start
,"hs_ed25519_secret_key"))
213 continue; // uninterested
220 while (*p
!= '\0' && *p
!= ' ')
229 if (len
!= ONION_LEN
||
230 base32_valid(p
,&cnt
) ||
231 cnt
!= BASE32_TO_LEN(PUBONION_LEN
) ||
232 strcmp(&p
[cnt
],".onion") != 0)
234 fprintf(stderr
,"ERROR: invalid hostname syntax\n");
237 if (!onehostname
|| !strcmp(onehostname
,p
)) {
238 memcpy(&sname
[direndpos
],p
,len
+ 1);
245 ? (len
!= B64_PUBKEY_LEN
|| !base64_valid(p
,0) ||
246 base64_from(pubbuf
,p
,len
) != FORMATTED_PUBLIC_LEN
)
247 : (len
!= B64_RAW_PUBKEY_LEN
|| !base64_valid(p
,0) ||
248 base64_from(&pubbuf
[PKPREFIX_SIZE
],p
,len
) != PUBLIC_LEN
))
250 fprintf(stderr
,"ERROR: invalid pubkey syntax\n");
257 ? (len
!= B64_SECKEY_LEN
|| !base64_valid(p
,0) ||
258 base64_from(secbuf
,p
,len
) != FORMATTED_SECRET_LEN
)
259 : (len
!= B64_RAW_SECKEY_LEN
|| !base64_valid(p
,0) ||
260 base64_from(&secbuf
[SKPREFIX_SIZE
],p
,len
) != SECRET_LEN
))
262 fprintf(stderr
,"ERROR: invalid seckey syntax\n");
268 if (hashost
&& haspub
&& hassec
) {
272 sigaddset(&nset
,SIGINT
);
273 sigaddset(&nset
,SIGTERM
);
274 sigprocmask(SIG_BLOCK
,&nset
,&oset
);
276 if (createdir(sname
,1) != 0) {
277 fprintf(stderr
,"ERROR: could not create directory for key output\n");
281 strcpy(&sname
[onionendpos
],"/hs_ed25519_secret_key");
282 writetofile(sname
,secbuf
,FORMATTED_SECRET_LEN
,1);
284 strcpy(&sname
[onionendpos
],"/hs_ed25519_public_key");
285 writetofile(sname
,pubbuf
,FORMATTED_PUBLIC_LEN
,0);
287 strcpy(&sname
[onionendpos
],"/hostname");
288 FILE *hfile
= fopen(sname
,"w");
289 sname
[onionendpos
] = '\n';
291 fwrite(&sname
[direndpos
],ONION_LEN
+ 1,1,hfile
);
295 fwrite(&sname
[printstartpos
],printlen
,1,fout
);
299 sigprocmask(SIG_SETMASK
,&oset
,0);
302 return 0; // finished
303 // skip rest of lines until we hit start of new doc indicator
309 fprintf(stderr
,"error while reading input\n");
314 fprintf(stderr
,"hostname wasn't found in input\n");