Merge pull request #1 from Tarnyko/master
[src/app-framework-main.git] / 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                 "\n",
67                 appname
68         );
69 }
70
71 static struct option options[] = {
72         { "key",         required_argument, NULL, 'k' },
73         { "certificate", required_argument, NULL, 'c' },
74         { "distributor", required_argument, NULL, 'd' },
75         { "author",      no_argument,       NULL, 'a' },
76         { "force",       no_argument,       NULL, 'f' },
77         { "help",        no_argument,       NULL, 'h' },
78         { NULL, 0, NULL, 0 }
79 };
80
81 /* install the widgets of the list */
82 int main(int ac, char **av)
83 {
84         int i, force, ncert, author;
85         unsigned int number;
86         char *keyfile, *certfiles[MAXCERT+1], *directory, **x;
87         struct stat s;
88
89         openlog(appname, LOG_PERROR, LOG_USER);
90
91         force = ncert = author = 0;
92         number = UINT_MAX;
93         keyfile = directory = NULL;
94         for (;;) {
95                 i = getopt_long(ac, av, "hfak:c:d:", options, NULL);
96                 if (i < 0)
97                         break;
98                 switch (i) {
99                 case 'c':
100                         if (ncert == MAXCERT) {
101                                 syslog(LOG_ERR, "maximum count of certificates reached");
102                                 return 1;
103                         }
104                         certfiles[ncert++] = optarg;
105                         continue;
106                 case 'k': x = &keyfile; break;
107                 case 'd': number = get_number(optarg); continue;
108                 case 'f': force = 1; continue;
109                 case 'a': author = 1; continue;
110                 case 'h': usage(); return 0;
111                 case ':':
112                         syslog(LOG_ERR, "missing argument");
113                         return 1;
114                 default:
115                         syslog(LOG_ERR, "unrecognized option");
116                         return 1;
117                 }
118                 if (*x != NULL) {
119                         syslog(LOG_ERR, "option set twice");
120                         return 1;
121                 }
122                 *x = optarg;
123         }
124
125         /* remaining arguments and final checks */
126         if (optind >= ac) {
127                 syslog(LOG_ERR, "no directory set");
128                 return 1;
129         }
130         directory = av[optind++];
131         if (optind < ac) {
132                 syslog(LOG_ERR, "extra parameters found");
133                 return 1;
134         }
135
136         /* set default values */
137         if (keyfile == NULL)
138                 keyfile = DEFAULT_KEY_FILE;
139         if (ncert == 0)
140                 certfiles[ncert++] = DEFAULT_CERT_FILE;
141
142         /* check values */
143         if (stat(directory, &s)) {
144                 syslog(LOG_ERR, "can't find directory %s", directory);
145                 return 1;
146         }
147         if (!S_ISDIR(s.st_mode)) {
148                 syslog(LOG_ERR, "%s isn't a directory", directory);
149                 return 1;
150         }
151         if (access(keyfile, R_OK) != 0) {
152                 syslog(LOG_ERR, "can't access private key %s", keyfile);
153                 return 1;
154         }
155         for(i = 0 ; i < ncert ; i++) 
156                 if (access(certfiles[i], R_OK) != 0) {
157                         syslog(LOG_ERR, "can't access certificate %s", certfiles[i]);
158                         return 1;
159                 }
160
161         /* init xmlsec module */
162         if (xmlsec_init())
163                 return 1;
164
165
166         /* compute absolutes paths */
167 #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)
168         rp(keyfile);
169         for(i = 0 ; i < ncert ; i++) 
170                 rp(certfiles[i]);
171 #undef rp
172
173         /* set and enter the workdir */
174         if (set_workdir(directory, 0) || enter_workdir(0))
175                 return 1;
176
177         if (fill_files())
178                 return 1;
179
180         if (author)
181                 number = 0;
182         else if (number == UINT_MAX)
183                 for (number = 1; get_signature(number) != NULL ; number++);
184
185         if (!force && get_signature(number) != NULL) {
186                 syslog(LOG_ERR, "can't overwrite existing signature %s", get_signature(number)->name);
187                 return 1;
188         }
189
190 printf("\n\nSIGNING content of directory %s for number %u\n", directory, number);
191
192         certfiles[ncert] = NULL;
193         return !!create_digsig(number, keyfile, (const char**)certfiles);
194 }
195