fix help error
[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 <getopt.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #include "verbose.h"
29 #include "wgtpkg.h"
30
31 #if !defined(MAXCERT)
32 #define MAXCERT 20
33 #endif
34 #if !defined(DEFAULT_KEY_FILE)
35 #define DEFAULT_KEY_FILE "key.pem"
36 #endif
37 #if !defined(DEFAULT_CERT_FILE)
38 #define DEFAULT_CERT_FILE "cert.pem"
39 #endif
40
41 const char appname[] = "wgtpkg-sign";
42
43 static unsigned int get_number(const char *value)
44 {
45         char *end;
46         unsigned long int val;
47
48         val = strtoul(value, &end, 10);
49         if (*end || 0 == val || val >= UINT_MAX || *value == '-') {
50                 ERROR("bad number value %s", value);
51                 exit(1);
52         }
53         return (unsigned int)val;
54 }
55
56 static void usage()
57 {
58         printf(
59                 "usage: %s [-f] [-k keyfile] [-c certfile]... [-d number | -a] directory\n"
60                 "\n"
61                 "   -k keyfile       the private key to use for author signing\n"
62                 "   -c certfile      the certificate(s) to use for author signing\n"
63                 "   -d number        the number of the distributor signature (zero for automatic)\n"
64                 "   -a               the author signature\n"
65                 "   -f               force overwriting\n"
66                 "   -q               quiet\n"
67                 "   -v               verbose\n"
68                 "\n",
69                 appname
70         );
71 }
72
73 static struct option options[] = {
74         { "key",         required_argument, NULL, 'k' },
75         { "certificate", required_argument, NULL, 'c' },
76         { "distributor", required_argument, NULL, 'd' },
77         { "author",      no_argument,       NULL, 'a' },
78         { "force",       no_argument,       NULL, 'f' },
79         { "help",        no_argument,       NULL, 'h' },
80         { "quiet",       no_argument,       NULL, 'q' },
81         { "verbose",     no_argument,       NULL, 'v' },
82         { NULL, 0, NULL, 0 }
83 };
84
85 /* install the widgets of the list */
86 int main(int ac, char **av)
87 {
88         int i, force, ncert, author;
89         unsigned int number;
90         char *keyfile, *certfiles[MAXCERT+1], *directory, **x;
91         struct stat s;
92
93         LOGUSER(appname);
94
95         force = ncert = author = 0;
96         number = UINT_MAX;
97         keyfile = directory = NULL;
98         for (;;) {
99                 i = getopt_long(ac, av, "hfqvak:c:d:", options, NULL);
100                 if (i < 0)
101                         break;
102                 switch (i) {
103                 case 'c':
104                         if (ncert == MAXCERT) {
105                                 ERROR("maximum count of certificates reached");
106                                 return 1;
107                         }
108                         certfiles[ncert++] = optarg;
109                         continue;
110                 case 'k': x = &keyfile; break;
111                 case 'd': number = get_number(optarg); continue;
112                 case 'f': force = 1; continue;
113                 case 'a': author = 1; continue;
114                 case 'h': usage(); return 0;
115                 case 'q':
116                         if (verbosity)
117                                 verbosity--;
118                         break;
119                 case 'v':
120                         verbosity++;
121                         break;
122                 case ':':
123                         ERROR("missing argument");
124                         return 1;
125                 default:
126                         ERROR("unrecognized option");
127                         return 1;
128                 }
129                 if (*x != NULL) {
130                         ERROR("option set twice");
131                         return 1;
132                 }
133                 *x = optarg;
134         }
135
136         /* remaining arguments and final checks */
137         if (optind >= ac) {
138                 ERROR("no directory set");
139                 return 1;
140         }
141         directory = av[optind++];
142         if (optind < ac) {
143                 ERROR("extra parameters found");
144                 return 1;
145         }
146
147         /* set default values */
148         if (keyfile == NULL)
149                 keyfile = DEFAULT_KEY_FILE;
150         if (ncert == 0)
151                 certfiles[ncert++] = DEFAULT_CERT_FILE;
152
153         /* check values */
154         if (stat(directory, &s)) {
155                 ERROR("can't find directory %s", directory);
156                 return 1;
157         }
158         if (!S_ISDIR(s.st_mode)) {
159                 ERROR("%s isn't a directory", directory);
160                 return 1;
161         }
162         if (access(keyfile, R_OK) != 0) {
163                 ERROR("can't access private key %s", keyfile);
164                 return 1;
165         }
166         for(i = 0 ; i < ncert ; i++) 
167                 if (access(certfiles[i], R_OK) != 0) {
168                         ERROR("can't access certificate %s", certfiles[i]);
169                         return 1;
170                 }
171
172         /* init xmlsec module */
173         if (xmlsec_init())
174                 return 1;
175
176
177         /* compute absolutes paths */
178 #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)
179         rp(keyfile);
180         for(i = 0 ; i < ncert ; i++) 
181                 rp(certfiles[i]);
182 #undef rp
183
184         /* set and enter the workdir */
185         if (set_workdir(directory, 0))
186                 return 1;
187
188         if (fill_files())
189                 return 1;
190
191         if (author)
192                 number = 0;
193         else if (number == UINT_MAX)
194                 for (number = 1; get_signature(number) != NULL ; number++);
195
196         if (!force && get_signature(number) != NULL) {
197                 ERROR("can't overwrite existing signature %s", get_signature(number)->name);
198                 return 1;
199         }
200
201         NOTICE("-- SIGNING content of directory %s for number %u", directory, number);
202
203         certfiles[ncert] = NULL;
204         return !!create_digsig(number, keyfile, (const char**)certfiles);
205 }
206