1 #define _POSIX_C_SOURCE 200112L
22 #define LINEFEED_LEN (sizeof(char))
23 #define NULLTERM_LEN (sizeof(char))
24 #define PATH_SEPARATOR_LEN (sizeof(char))
26 static const char keys_field_generated
[] = "---";
27 static const char keys_field_hostname
[] = "hostname: ";
28 static const char keys_field_publickey
[] = "hs_ed25519_public_key: ";
29 static const char keys_field_secretkey
[] = "hs_ed25519_secret_key: ";
30 static const char keys_field_time
[] = "time: ";
32 #define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
33 #define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
34 #define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
35 #define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
36 #define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
38 #define B64_PUBKEY_LEN (BASE64_TO_LEN(FORMATTED_PUBLIC_LEN))
39 #define B64_SECKEY_LEN (BASE64_TO_LEN(FORMATTED_SECRET_LEN))
40 #define TIME_LEN (21 * sizeof(char)) // strlen("2018-07-04 21:31:20 Z")
43 KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN + \
44 KEYS_FIELD_HOSTNAME_LEN + ONION_LEN + LINEFEED_LEN + \
45 KEYS_FIELD_PUBLICKEY_LEN + B64_PUBKEY_LEN + LINEFEED_LEN + \
46 KEYS_FIELD_SECRETKEY_LEN + B64_SECKEY_LEN + LINEFEED_LEN + \
47 KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
50 static pthread_mutex_t tminfo_mutex
;
54 pthread_mutex_init(&tminfo_mutex
,0);
59 pthread_mutex_destroy(&tminfo_mutex
);
62 #define BUF_APPEND(buf,offset,src,srclen) \
64 memcpy(&buf[offset],(src),(srclen)); \
67 #define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
68 #define BUF_APPEND_CHAR(buf,offset,c) buf[offset++] = (c)
70 void yamlout_writekeys(const char *hostname
,const u8
*formated_public
,const u8
*formated_secret
)
72 char keysbuf
[KEYS_LEN
];
73 char pubkeybuf
[B64_PUBKEY_LEN
+ NULLTERM_LEN
];
74 char seckeybuf
[B64_SECKEY_LEN
+ NULLTERM_LEN
];
75 char timebuf
[TIME_LEN
+ NULLTERM_LEN
];
78 BUF_APPEND(keysbuf
,offset
,keys_field_generated
,KEYS_FIELD_GENERATED_LEN
);
79 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
81 BUF_APPEND(keysbuf
,offset
,keys_field_hostname
,KEYS_FIELD_HOSTNAME_LEN
);
82 BUF_APPEND(keysbuf
,offset
,hostname
,ONION_LEN
);
83 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
85 BUF_APPEND(keysbuf
,offset
,keys_field_publickey
,KEYS_FIELD_PUBLICKEY_LEN
);
86 base64_to(pubkeybuf
,formated_public
,FORMATTED_PUBLIC_LEN
);
87 BUF_APPEND(keysbuf
,offset
,pubkeybuf
,B64_PUBKEY_LEN
);
88 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
90 BUF_APPEND(keysbuf
,offset
,keys_field_secretkey
,KEYS_FIELD_SECRETKEY_LEN
);
91 base64_to(seckeybuf
,formated_secret
,FORMATTED_SECRET_LEN
);
92 BUF_APPEND(keysbuf
,offset
,seckeybuf
,B64_SECKEY_LEN
);
93 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
95 BUF_APPEND(keysbuf
,offset
,keys_field_time
,KEYS_FIELD_TIME_LEN
);
101 pthread_mutex_lock(&tminfo_mutex
);
102 tm_info
= gmtime(&currtime
);
103 strftime(timebuf
,sizeof(timebuf
),"%Y-%m-%d %H:%M:%S Z",tm_info
);
104 pthread_mutex_unlock(&tminfo_mutex
);
106 BUF_APPEND(keysbuf
,offset
,timebuf
,TIME_LEN
);
107 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
109 assert(offset
== KEYS_LEN
);
111 pthread_mutex_lock(&fout_mutex
);
112 fwrite(keysbuf
,sizeof(keysbuf
),1,fout
);
114 pthread_mutex_unlock(&fout_mutex
);
117 #undef BUF_APPEND_CHAR
118 #undef BUF_APPEND_CSTR
121 // pseudo YAML parser
122 int yamlin_parseandcreate(FILE *fin
,char *sname
,const char *hostname
)
126 u8 pubbuf
[BASE64_DATA_ALIGN(FORMATTED_PUBLIC_LEN
)];
127 u8 secbuf
[BASE64_DATA_ALIGN(FORMATTED_SECRET_LEN
)];
128 int hashost
= 0,haspub
= 0,hassec
= 0,skipthis
= 0;
129 enum keytype
{ HOST
, PUB
, SEC
} keyt
;
131 while (!feof(fin
) && !ferror(fin
)) {
132 if (!fgets(line
,sizeof(line
),fin
))
137 // trim whitespace from the end
138 while (len
!= 0 && (line
[len
-1] == ' ' || line
[len
-1] == '\n' || line
[len
-1] == '\r'))
145 if (len
>= 3 && line
[0] == '-' && line
[1] == '-' && line
[2] == '-') {
146 // end of document indicator
147 if (!skipthis
&& (hashost
|| haspub
|| hassec
)) {
148 fprintf(stderr
,"ERROR: incomplete record\n");
151 hashost
= haspub
= hassec
= skipthis
= 0;
160 while (len
!= 0 && *start
== ' ') {
166 for (;*p
!= '\0';++p
) {
173 fprintf(stderr
,"ERROR: invalid syntax\n");
174 return 1; // XXX could continue too there but eh
178 if (!strcmp(start
,"hostname"))
180 else if (!strcmp(start
,"hs_ed25519_public_key"))
182 else if (!strcmp(start
,"hs_ed25519_secret_key"))
185 continue; // uninterested
192 while (*p
!= '\0' && *p
!= ' ')
201 if (len
!= ONION_LEN
||
202 base32_valid(p
,&cnt
) ||
203 cnt
!= BASE32_TO_LEN(PUBONION_LEN
) ||
204 strcmp(&p
[cnt
],".onion") != 0)
206 fprintf(stderr
,"ERROR: invalid hostname syntax\n");
209 if (!hostname
|| !strcmp(hostname
,p
)) {
210 memcpy(&sname
[direndpos
],p
,len
+ 1);
216 if (len
!= B64_PUBKEY_LEN
|| !base64_valid(p
,0) ||
217 base64_from(pubbuf
,p
,len
) != FORMATTED_PUBLIC_LEN
)
219 fprintf(stderr
,"ERROR: invalid pubkey syntax\n");
225 if (len
!= B64_SECKEY_LEN
|| !base64_valid(p
,0) ||
226 base64_from(secbuf
,p
,len
) != FORMATTED_SECRET_LEN
)
228 fprintf(stderr
,"ERROR: invalid seckey syntax\n");
234 if (hashost
&& haspub
&& hassec
) {
238 sigaddset(&nset
,SIGINT
);
239 sigaddset(&nset
,SIGTERM
);
240 sigprocmask(SIG_BLOCK
,&nset
,&oset
);
242 if (createdir(sname
,1) != 0) {
243 fprintf(stderr
,"ERROR: could not create directory for key output\n");
247 strcpy(&sname
[onionendpos
],"/hs_ed25519_secret_key");
248 writetofile(sname
,secbuf
,FORMATTED_SECRET_LEN
,1);
250 strcpy(&sname
[onionendpos
],"/hs_ed25519_public_key");
251 writetofile(sname
,pubbuf
,FORMATTED_PUBLIC_LEN
,0);
253 strcpy(&sname
[onionendpos
],"/hostname");
254 FILE *hfile
= fopen(sname
,"w");
255 sname
[onionendpos
] = '\n';
257 fwrite(&sname
[direndpos
],ONION_LEN
+ 1,1,hfile
);
261 fwrite(&sname
[printstartpos
],printlen
,1,fout
);
265 sigprocmask(SIG_SETMASK
,&oset
,0);
268 return 0; // finished
274 fprintf(stderr
,"error while reading input\n");
279 fprintf(stderr
,"hostname wasn't found in input\n");