Initial commit of vpp code.
[vpp.git] / vppversion / sign.c
1 /*
2  *------------------------------------------------------------------
3  * sign.c - sign a binary
4  * 
5  * Jan 2010, George Spelvin
6  * 
7  * Copyright (c) 2010 Cisco and/or its affiliates.
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at:
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *------------------------------------------------------------------
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <netinet/in.h>
28 #include <signal.h>
29 #include <pthread.h>
30 #include <unistd.h>
31 #include <time.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <vppinfra/clib.h>
35 #include <vppinfra/vec.h>
36 #include <vppinfra/hash.h>
37 #include <vppinfra/bitmap.h>
38 #include <vppinfra/fifo.h>
39 #include <vppinfra/time.h>
40 #include <vppinfra/mheap.h>
41 #include <vppinfra/heap.h>
42 #include <vppinfra/pool.h>
43 #include <vppinfra/format.h>
44 #include <vppinfra/error.h>
45 #include <vppinfra/unix.h>
46
47 /* Elf-file magic number */
48 static unsigned char elfmag[4] = {0x7F, 'E', 'L', 'F'};
49
50 int add_signature (char *file, u8 *sigfile)
51 {
52     clib_error_t *e;
53     u8 *sigcontents;
54     uword siglen;
55     struct stat statb;
56     int fd;
57     char magic[4];
58     int i;
59
60     if ((e = unix_file_contents ((char *)sigfile, &sigcontents))) {
61         fformat(stderr, "%v", e->what);
62         clib_error_free (e);
63         return 1;
64     }
65
66     siglen = vec_len (sigcontents);
67
68     vec_add1(sigcontents, (siglen>>24)&0xff);
69     vec_add1(sigcontents, (siglen>>16)&0xff);
70     vec_add1(sigcontents, (siglen>> 8)&0xff);
71     vec_add1(sigcontents, (siglen>> 0)&0xff);
72     
73     /* remember the desired file mode */
74     if (stat(file, &statb) < 0) {
75         fformat(stderr, "Couldn't stat %s\n", file);
76         return 1;
77     }
78     /* Skip empty / short trout. Don't complain */
79     if (statb.st_size < 4) {
80         return 0;
81     }
82
83     /* make it writeable */
84     chmod (file, 0777);
85
86     fd = open (file, O_RDWR | O_APPEND, 0755);
87     
88     if (fd < 0) {
89         fformat (stderr, "Couldn't append to %s\n", file);
90         return 1;
91     }
92
93     /* 
94      * We feed this program a list of files with execute permission.
95      * Signing a shell script makes it taste bad, etc. etc.
96      */
97     if (read(fd, magic, 4) != 4) {
98         fformat (stderr, "Couldn't read magic number from %s\n", file);
99     }
100
101     for (i = 0; i < 4; i++) {
102         if (magic[i] != elfmag[i]) {
103             goto skip_write;
104         }
105     }
106
107     if (write (fd, sigcontents, vec_len(sigcontents)) 
108         != vec_len (sigcontents)) {
109         fformat (stderr, "Write error on %s\n", file);
110         return 1;
111     }
112
113  skip_write:
114     close(fd);
115
116     /* restore the file mode */
117     chmod (file, statb.st_mode);
118
119     return 0;
120 }
121
122 int mypid;
123
124 int sign_one_file (char *pemfile, char *password, char *file)
125 {
126     u8 *cmd;
127     u8 *t1, *t2;
128
129     t1 = format (0, "/tmp/sha256-%d%c", mypid, 0);
130     t2 = format (0, "/tmp/sig-%d%c", mypid, 0);
131
132     cmd = format (0, "openssl dgst -sha256 < %s > %s%c", file, t1, 0);
133     if (system((char *)cmd)) {
134     barf:
135         clib_warning("'%s' failed", cmd);
136         return 1;
137     }
138     vec_free(cmd);
139
140     cmd = format (0, "openssl rsautl -inkey %s -in %s -out %s ",
141                   pemfile, t1, t2);
142     cmd = format (cmd, "-passin pass:%s -sign%c", password, 0);
143
144     if (system((char *)cmd))
145         goto barf;
146
147     vec_free(cmd);
148
149     if (add_signature (file, t2))
150         return 1;
151
152     unlink ((char *)t1);
153     unlink ((char *)t2);
154
155     return (0);
156 }
157
158 /* usage: sign <foo.pem> <password> <list-of-files> */
159
160 int main (int argc, char **argv)
161 {
162     int i;
163     mypid = getpid();
164
165     if (argc < 4) {
166         fformat(stderr, "usage: %s <xxx.pem> <password> <list-of-files>\n", 
167                 argv[0]);
168         exit (1);
169     }
170
171     for (i = 3; i < argc; i++) {
172         if (sign_one_file (argv[1], argv[2], argv[i])) {
173             fformat(stderr, "Left unsigned: %s\n", argv[i]);
174         }
175     }
176
177     exit (0);
178 }