work in progress
[src/app-framework-main.git] / src / wgtpkg-sign.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <limits.h>
23 #include <errno.h>
24 #include <syslog.h>
25 #include <getopt.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #include "verbose.h"
30 #include "wgtpkg.h"
31
32 #if !defined(MAXCERT)
33 #define MAXCERT 20
34 #endif
35 #if !defined(DEFAULT_KEY_FILE)
36 #define DEFAULT_KEY_FILE "key.pem"
37 #endif
38 #if !defined(DEFAULT_CERT_FILE)
39 #define DEFAULT_CERT_FILE "cert.pem"
40 #endif
41
42 const char appname[] = "wgtpkg-sign";
43
44 static unsigned int get_number(const char *value)
45 {
46         char *end;
47         unsigned long int val;
48
49         val = strtoul(value, &end, 10);
50         if (*end || 0 == val || val >= UINT_MAX || *value == '-') {
51                 ERROR("bad number value %s", value);
52                 exit(1);
53         }
54         return (unsigned int)val;
55 }
56
57 static void usage()
58 {
59         printf(
60                 "usage: %s [-f] [-k keyfile] [-c certfile]... [-o wgtfile] [-d number | -a] directory\n"
61                 "\n"
62                 "   -k keyfile       the private key to use for author signing\n"
63                 "   -c certfile      the certificate(s) to use for author signing\n"
64                 "   -d number        the number of the distributor signature (zero for automatic)\n"
65                 "   -a               the author signature\n"
66                 "   -f               force overwriting\n"
67                 "   -q               quiet\n"
68                 "   -v               verbose\n"
69                 "\n",
70                 appname
71         );
72 }
73
74 static struct option options[] = {
75         { "key",         required_argument, NULL, 'k' },
76         { "certificate", required_argument, NULL, 'c' },
77         { "distributor", required_argument, NULL, 'd' },
78         { "author",      no_argument,       NULL, 'a' },
79         { "force",       no_argument,       NULL, 'f' },
80         { "help",        no_argument,       NULL, 'h' },
81         { "quiet",       no_argument,       NULL, 'q' },
82         { "verbose",     no_argument,       NULL, 'v' },
83         { NULL, 0, NULL, 0 }
84 };
85
86 /* install the widgets of the list */
87 int main(int ac, char **av)
88 {
89         int i, force, ncert, author;
90         unsigned int number;
91         char *keyfile, *certfiles[MAXCERT+1], *directory, **x;
92         struct stat s;
93
94         openlog(appname, LOG_PERROR, LOG_USER);
95
96         force = ncert = author = 0;
97         number = UINT_MAX;
98         keyfile = directory = NULL;
99         for (;;) {
100                 i = getopt_long(ac, av, "hfqvak:c:d:", options, NULL);
101                 if (i < 0)
102                         break;
103                 switch (i) {
104                 case 'c':
105                         if (ncert == MAXCERT) {
106                                 ERROR("maximum count of certificates reached");
107                                 return 1;
108                         }
109                         certfiles[ncert++] = optarg;
110                         continue;
111                 case 'k': x = &keyfile; break;
112                 case 'd': number = get_number(optarg); continue;
113                 case 'f': force = 1; continue;
114                 case 'a': author = 1; continue;
115                 case 'h': usage(); return 0;
116                 case 'q':
117                         if (verbosity)
118                                 verbosity--;
119                         break;
120                 case 'v':
121                         verbosity++;
122                         break;
123                 case ':':
124                         ERROR("missing argument");
125                         return 1;
126                 default:
127                         ERROR("unrecognized option");
128                         return 1;
129                 }
130                 if (*x != NULL) {
131                         ERROR("option set twice");
132                         return 1;
133                 }
134                 *x = optarg;
135         }
136
137         /* remaining arguments and final checks */
138         if (optind >= ac) {
139                 ERROR("no directory set");
140                 return 1;
141         }
142         directory = av[optind++];
143         if (optind < ac) {
144                 ERROR("extra parameters found");
145                 return 1;
146         }
147
148         /* set default values */
149         if (keyfile == NULL)
150                 keyfile = DEFAULT_KEY_FILE;
151         if (ncert == 0)
152                 certfiles[ncert++] = DEFAULT_CERT_FILE;
153
154         /* check values */
155         if (stat(directory, &s)) {
156                 ERROR("can't find directory %s", directory);
157                 return 1;
158         }
159         if (!S_ISDIR(s.st_mode)) {
160                 ERROR("%s isn't a directory", directory);
161                 return 1;
162         }
163         if (access(keyfile, R_OK) != 0) {
164                 ERROR("can't access private key %s", keyfile);
165                 return 1;
166         }
167         for(i = 0 ; i < ncert ; i++) 
168                 if (access(certfiles[i], R_OK) != 0) {
169                         ERROR("can't access certificate %s", certfiles[i]);
170                         return 1;
171                 }
172
173         /* init xmlsec module */
174         if (xmlsec_init())
175                 return 1;
176
177
178         /* compute absolutes paths */
179 #define rp(x) do { char *p = realpath(x, NULL); if (p != NULL) x = p; else { ERROR("realpath failed for %s",x); return 1; } } while(0)
180         rp(keyfile);
181         for(i = 0 ; i < ncert ; i++) 
182                 rp(certfiles[i]);
183 #undef rp
184
185         /* set and enter the workdir */
186         if (set_workdir(directory, 0))
187                 return 1;
188
189         if (fill_files())
190                 return 1;
191
192         if (author)
193                 number = 0;
194         else if (number == UINT_MAX)
195                 for (number = 1; get_signature(number) != NULL ; number++);
196
197         if (!force && get_signature(number) != NULL) {
198                 ERROR("can't overwrite existing signature %s", get_signature(number)->name);
199                 return 1;
200         }
201
202         NOTICE("-- SIGNING content of directory %s for number %u", directory, number);
203
204         certfiles[ncert] = NULL;
205         return !!create_digsig(number, keyfile, (const char**)certfiles);
206 }
207