refactoring sources
[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 "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                 syslog(LOG_ERR, "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]... [-o wgtfile] [-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         openlog(appname, LOG_PERROR, LOG_USER);
94
95         force = ncert = author = 0;
96         number = UINT_MAX;
97         keyfile = directory = NULL;
98         for (;;) {
99                 i = getopt_long(ac, av, "hfak:c:d:", options, NULL);
100                 if (i < 0)
101                         break;
102                 switch (i) {
103                 case 'c':
104                         if (ncert == MAXCERT) {
105                                 syslog(LOG_ERR, "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 ':':
116                         syslog(LOG_ERR, "missing argument");
117                         return 1;
118                 default:
119                         syslog(LOG_ERR, "unrecognized option");
120                         return 1;
121                 }
122                 if (*x != NULL) {
123                         syslog(LOG_ERR, "option set twice");
124                         return 1;
125                 }
126                 *x = optarg;
127         }
128
129         /* remaining arguments and final checks */
130         if (optind >= ac) {
131                 syslog(LOG_ERR, "no directory set");
132                 return 1;
133         }
134         directory = av[optind++];
135         if (optind < ac) {
136                 syslog(LOG_ERR, "extra parameters found");
137                 return 1;
138         }
139
140         /* set default values */
141         if (keyfile == NULL)
142                 keyfile = DEFAULT_KEY_FILE;
143         if (ncert == 0)
144                 certfiles[ncert++] = DEFAULT_CERT_FILE;
145
146         /* check values */
147         if (stat(directory, &s)) {
148                 syslog(LOG_ERR, "can't find directory %s", directory);
149                 return 1;
150         }
151         if (!S_ISDIR(s.st_mode)) {
152                 syslog(LOG_ERR, "%s isn't a directory", directory);
153                 return 1;
154         }
155         if (access(keyfile, R_OK) != 0) {
156                 syslog(LOG_ERR, "can't access private key %s", keyfile);
157                 return 1;
158         }
159         for(i = 0 ; i < ncert ; i++) 
160                 if (access(certfiles[i], R_OK) != 0) {
161                         syslog(LOG_ERR, "can't access certificate %s", certfiles[i]);
162                         return 1;
163                 }
164
165         /* init xmlsec module */
166         if (xmlsec_init())
167                 return 1;
168
169
170         /* compute absolutes paths */
171 #define rp(x) do { char *p = realpath(x, NULL); if (p != NULL) x = p; else { syslog(LOG_ERR, "realpath failed for %s",x); return 1; } } while(0)
172         rp(keyfile);
173         for(i = 0 ; i < ncert ; i++) 
174                 rp(certfiles[i]);
175 #undef rp
176
177         /* set and enter the workdir */
178         if (set_workdir(directory, 0) || enter_workdir(0))
179                 return 1;
180
181         if (fill_files())
182                 return 1;
183
184         if (author)
185                 number = 0;
186         else if (number == UINT_MAX)
187                 for (number = 1; get_signature(number) != NULL ; number++);
188
189         if (!force && get_signature(number) != NULL) {
190                 syslog(LOG_ERR, "can't overwrite existing signature %s", get_signature(number)->name);
191                 return 1;
192         }
193
194         notice("-- SIGNING content of directory %s for number %u", directory, number);
195
196         certfiles[ncert] = NULL;
197         return !!create_digsig(number, keyfile, (const char**)certfiles);
198 }
199