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