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