2 #define _POSIX_C_SOURCE 200112L
24 #define LINEFEED_LEN (sizeof(char))
25 #define NULLTERM_LEN (sizeof(char))
26 #define PATH_SEPARATOR_LEN (sizeof(char))
28 static const char keys_field_generated
[] = "---";
29 static const char keys_field_hostname
[] = "hostname: ";
30 static const char keys_field_publickey
[] = "hs_ed25519_public_key: ";
31 static const char keys_field_secretkey
[] = "hs_ed25519_secret_key: ";
32 static const char keys_field_time
[] = "time: ";
34 #define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
35 #define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
36 #define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
37 #define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
38 #define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
40 #define B64_PUBKEY_LEN (BASE64_TO_LEN(FORMATTED_PUBLIC_LEN))
41 #define B64_SECKEY_LEN (BASE64_TO_LEN(FORMATTED_SECRET_LEN))
42 #define TIME_LEN (21 * sizeof(char)) // strlen("2018-07-04 21:31:20 Z")
45 KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN + \
46 KEYS_FIELD_HOSTNAME_LEN + ONION_LEN + LINEFEED_LEN + \
47 KEYS_FIELD_PUBLICKEY_LEN + B64_PUBKEY_LEN + LINEFEED_LEN + \
48 KEYS_FIELD_SECRETKEY_LEN + B64_SECKEY_LEN + LINEFEED_LEN + \
49 KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
52 static pthread_mutex_t tminfo_mutex
;
56 pthread_mutex_init(&tminfo_mutex
,0);
61 pthread_mutex_destroy(&tminfo_mutex
);
64 #define BUF_APPEND(buf,offset,src,srclen) \
66 memcpy(&buf[offset],(src),(srclen)); \
69 #define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
70 #define BUF_APPEND_CHAR(buf,offset,c) buf[offset++] = (c)
72 void yamlout_writekeys(const char *hostname
,const u8
*formated_public
,const u8
*formated_secret
)
74 char keysbuf
[KEYS_LEN
];
75 char pubkeybuf
[B64_PUBKEY_LEN
+ NULLTERM_LEN
];
76 char seckeybuf
[B64_SECKEY_LEN
+ NULLTERM_LEN
];
77 char timebuf
[TIME_LEN
+ NULLTERM_LEN
];
80 BUF_APPEND(keysbuf
,offset
,keys_field_generated
,KEYS_FIELD_GENERATED_LEN
);
81 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
83 BUF_APPEND(keysbuf
,offset
,keys_field_hostname
,KEYS_FIELD_HOSTNAME_LEN
);
84 BUF_APPEND(keysbuf
,offset
,hostname
,ONION_LEN
);
85 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
87 BUF_APPEND(keysbuf
,offset
,keys_field_publickey
,KEYS_FIELD_PUBLICKEY_LEN
);
88 base64_to(pubkeybuf
,formated_public
,FORMATTED_PUBLIC_LEN
);
89 BUF_APPEND(keysbuf
,offset
,pubkeybuf
,B64_PUBKEY_LEN
);
90 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
92 BUF_APPEND(keysbuf
,offset
,keys_field_secretkey
,KEYS_FIELD_SECRETKEY_LEN
);
93 base64_to(seckeybuf
,formated_secret
,FORMATTED_SECRET_LEN
);
94 BUF_APPEND(keysbuf
,offset
,seckeybuf
,B64_SECKEY_LEN
);
95 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
97 BUF_APPEND(keysbuf
,offset
,keys_field_time
,KEYS_FIELD_TIME_LEN
);
103 pthread_mutex_lock(&tminfo_mutex
);
104 tm_info
= gmtime(&currtime
);
105 strftime(timebuf
,sizeof(timebuf
),"%Y-%m-%d %H:%M:%S Z",tm_info
);
106 pthread_mutex_unlock(&tminfo_mutex
);
108 BUF_APPEND(keysbuf
,offset
,timebuf
,TIME_LEN
);
109 BUF_APPEND_CHAR(keysbuf
,offset
,'\n');
111 assert(offset
== KEYS_LEN
);
113 pthread_mutex_lock(&fout_mutex
);
114 fwrite(keysbuf
,sizeof(keysbuf
),1,fout
);
116 pthread_mutex_unlock(&fout_mutex
);
119 #undef BUF_APPEND_CHAR
120 #undef BUF_APPEND_CSTR
123 // pseudo YAML parser
124 int yamlin_parseandcreate(FILE *fin
,char *sname
,const char *hostname
)
128 u8 pubbuf
[BASE64_DATA_ALIGN(FORMATTED_PUBLIC_LEN
)];
129 u8 secbuf
[BASE64_DATA_ALIGN(FORMATTED_SECRET_LEN
)];
130 int hashost
= 0,haspub
= 0,hassec
= 0,skipthis
= 0;
131 enum keytype
{ HOST
, PUB
, SEC
} keyt
;
133 while (!feof(fin
) && !ferror(fin
)) {
134 if (!fgets(line
,sizeof(line
),fin
))
139 // trim whitespace from the end
140 while (len
!= 0 && (line
[len
-1] == ' ' || line
[len
-1] == '\n' || line
[len
-1] == '\r'))
147 if (len
>= 3 && line
[0] == '-' && line
[1] == '-' && line
[2] == '-') {
148 // end of document indicator
149 if (!skipthis
&& (hashost
|| haspub
|| hassec
)) {
150 fprintf(stderr
,"ERROR: incomplete record\n");
153 hashost
= haspub
= hassec
= skipthis
= 0;
162 while (len
!= 0 && *start
== ' ') {
168 for (;*p
!= '\0';++p
) {
175 fprintf(stderr
,"ERROR: invalid syntax\n");
176 return 1; // XXX could continue too there but eh
180 if (!strcmp(start
,"hostname"))
182 else if (!strcmp(start
,"hs_ed25519_public_key"))
184 else if (!strcmp(start
,"hs_ed25519_secret_key"))
187 continue; // uninterested
194 while (*p
!= '\0' && *p
!= ' ')
203 if (len
!= ONION_LEN
||
204 base32_valid(p
,&cnt
) ||
205 cnt
!= BASE32_TO_LEN(PUBONION_LEN
) ||
206 strcmp(&p
[cnt
],".onion") != 0)
208 fprintf(stderr
,"ERROR: invalid hostname syntax\n");
211 if (!hostname
|| !strcmp(hostname
,p
)) {
212 memcpy(&sname
[direndpos
],p
,len
+ 1);
218 if (len
!= B64_PUBKEY_LEN
|| !base64_valid(p
,0) ||
219 base64_from(pubbuf
,p
,len
) != FORMATTED_PUBLIC_LEN
)
221 fprintf(stderr
,"ERROR: invalid pubkey syntax\n");
227 if (len
!= B64_SECKEY_LEN
|| !base64_valid(p
,0) ||
228 base64_from(secbuf
,p
,len
) != FORMATTED_SECRET_LEN
)
230 fprintf(stderr
,"ERROR: invalid seckey syntax\n");
236 if (hashost
&& haspub
&& hassec
) {
240 sigaddset(&nset
,SIGINT
);
241 sigaddset(&nset
,SIGTERM
);
242 sigprocmask(SIG_BLOCK
,&nset
,&oset
);
244 if (createdir(sname
,1) != 0) {
245 fprintf(stderr
,"ERROR: could not create directory for key output\n");
249 strcpy(&sname
[onionendpos
],"/hs_ed25519_secret_key");
250 writetofile(sname
,secbuf
,FORMATTED_SECRET_LEN
,1);
252 strcpy(&sname
[onionendpos
],"/hs_ed25519_public_key");
253 writetofile(sname
,pubbuf
,FORMATTED_PUBLIC_LEN
,0);
255 strcpy(&sname
[onionendpos
],"/hostname");
256 FILE *hfile
= fopen(sname
,"w");
257 sname
[onionendpos
] = '\n';
259 fwrite(&sname
[direndpos
],ONION_LEN
+ 1,1,hfile
);
263 fwrite(&sname
[printstartpos
],printlen
,1,fout
);
267 sigprocmask(SIG_SETMASK
,&oset
,0);
270 return 0; // finished
276 fprintf(stderr
,"error while reading input\n");
281 fprintf(stderr
,"hostname wasn't found in input\n");