4 author: José Bollo <jose.bollo@iot.bzh>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
27 #include <libxml/tree.h>
28 #include <xmlsec/xmlsec.h>
29 #include <xmlsec/xmltree.h>
30 #include <xmlsec/xmldsig.h>
31 #include <xmlsec/crypto.h>
32 #include <xmlsec/templates.h>
33 #include <xmlsec/errors.h>
34 #include <xmlsec/io.h>
38 #include "wgtpkg-files.h"
39 #include "wgtpkg-workdir.h"
40 #include "wgtpkg-xmlsec.h"
42 static int initstatus;
44 static xmlSecKeysMngrPtr keymgr;
46 static const char trusted_certificates_directory[] = WGTPKG_TRUSTED_CERT_DIR;
48 /* checks if a file match uri (should not be a distributor signature) */
49 static int file_match_cb(const char *uri)
51 struct filedesc *fdesc = file_of_name(uri);
52 return fdesc != NULL && fdesc->type == type_file && (fdesc->flags & flag_distributor_signature) == 0;
55 /* open the file of uri */
56 static void *file_open_cb(const char *file)
58 struct filedesc *fdesc;
62 fdesc = file_of_name(file);
64 ERROR("shouldn't open uri %s", file);
68 fd = openat(workdirfd, file, O_RDONLY);
69 f = fd < 0 ? NULL : fdopen(fd, "r");
71 ERROR("can't open file %s for reading", file);
75 fdesc->flags |= flag_opened;
80 /* read the opened file */
81 static int file_read_cb(void *context, char *buffer, int len)
83 size_t r = fread(buffer, 1, len, (FILE*)context);
84 return r ? (int)r : feof((FILE*)context) ? 0 : - 1;
87 /* close the opened file */
88 static int file_close_cb(void *context)
90 return (int)fclose((FILE*)context);
93 /* echo an error message */
94 static void errors_cb(const char *file, int line, const char *func, const char *errorObject, const char *errorSubject, int reason, const char *msg)
96 ERROR("xmlSec error %3d: %s (subject=\"%s\", object=\"%s\")", reason, msg, errorSubject ? errorSubject : "?", errorObject ? errorObject : "?");
99 /* fills database with trusted keys */
100 static int fill_trusted_keys_file(const char *file)
102 int err = xmlSecCryptoAppKeysMngrCertLoad(keymgr, file, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted);
104 ERROR("xmlSecCryptoAppKeysMngrCertLoadMemory failed for %s", file);
110 /* fills database with trusted keys */
111 static int fill_trusted_keys_dir(const char *directory)
116 char path[PATH_MAX], *e;
118 e = stpcpy(path, directory);
121 ERROR("opendir %s failed in fill_trusted_keys_dir", path);
127 while (ent != NULL) {
128 if (ent->d_type == DT_REG) {
129 strcpy(e, ent->d_name);
130 err = fill_trusted_keys_file(path);
144 /* initialisation of access to xmlsec */
154 if(xmlSecInit() < 0) {
155 ERROR("xmlSecInit failed.");
159 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
160 if(xmlSecCryptoDLLoadLibrary(XMLSEC_CRYPTO) < 0) {
161 ERROR("xmlSecCryptoDLLoadLibrary %s failed.", XMLSEC_CRYPTO);
166 if(xmlSecCryptoAppInit(NULL) < 0) {
167 ERROR("xmlSecCryptoAppInit failed.");
171 if(xmlSecCryptoInit() < 0) {
172 ERROR("xmlSecCryptoInit failed.");
176 xmlSecErrorsSetCallback(errors_cb);
178 xmlSecIOCleanupCallbacks();
179 if (xmlSecIORegisterCallbacks(file_match_cb,
180 file_open_cb, file_read_cb, file_close_cb)) {
181 ERROR("xmlSecIORegisterCallbacks failed.");
185 keymgr = xmlSecKeysMngrCreate();
186 if (keymgr == NULL) {
187 ERROR("xmlSecKeysMngrCreate failed.");
191 if(xmlSecCryptoAppDefaultKeysMngrInit(keymgr) < 0) {
192 ERROR("xmlSecCryptoAppDefaultKeysMngrInit failed.");
195 fill_trusted_keys_dir(trusted_certificates_directory);
202 /* shuting down accesses to xmlsec */
203 void xmlsec_shutdown()
205 xmlSecKeysMngrDestroy(keymgr);
207 xmlSecCryptoShutdown();
209 xmlSecCryptoAppShutdown();
214 /* verify a signature */
215 int xmlsec_verify(xmlNodePtr node)
218 xmlSecDSigCtxPtr dsigctx;
220 assert(initdone && !initstatus);
222 dsigctx = xmlSecDSigCtxCreate(keymgr);
223 if (dsigctx == NULL) {
224 ERROR("xmlSecDSigCtxCreate failed.");
227 rc = xmlSecDSigCtxVerify(dsigctx, node);
229 ERROR("xmlSecDSigCtxVerify failed.");
230 else if (dsigctx->status != xmlSecDSigStatusSucceeded) {
231 ERROR("invalid signature.");
234 xmlSecDSigCtxDestroy(dsigctx);
240 /* templates for properties of signature files */
241 static const struct { const char *id; const char *xml; } properties[2] = {
243 .id = "AuthorSignature", /* template of properties for author signature */
245 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
246 "<SignatureProperty Id=\"profile\" Target=\"#AuthorSignature\">"
247 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
248 "</SignatureProperty>"
249 "<SignatureProperty Id=\"role\" Target=\"#AuthorSignature\">"
250 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-author\"></dsp:Role>"
251 "</SignatureProperty>"
252 "<SignatureProperty Id=\"identifier\" Target=\"#AuthorSignature\">"
253 "<dsp:Identifier></dsp:Identifier>"
254 "</SignatureProperty>"
255 "</SignatureProperties>"
258 .id = "DistributorSignature", /* template of properties for distributor signature */
260 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
261 "<SignatureProperty Id=\"profile\" Target=\"#DistributorSignature\">"
262 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
263 "</SignatureProperty>"
264 "<SignatureProperty Id=\"role\" Target=\"#DistributorSignature\">"
265 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-distributor\"></dsp:Role>"
266 "</SignatureProperty>"
267 "<SignatureProperty Id=\"identifier\" Target=\"#DistributorSignature\">"
268 "<dsp:Identifier></dsp:Identifier>"
269 "</SignatureProperty>"
270 "</SignatureProperties>"
274 /* create a signature of 'index' (0 for author, other values for distributors)
275 using the private 'key' (filename) and the certificates 'certs' (filenames)
277 xmlDocPtr xmlsec_create(int index, const char *key, const char **certs)
279 unsigned int i, fc, mask;
280 struct filedesc *fdesc;
281 xmlNodePtr sign, obj, ref, kinfo, props;
284 xmlSecDSigCtxPtr dsigctx;
286 assert(initdone && !initstatus);
288 /* create the document */
289 doc = xmlNewDoc("1.0");
291 ERROR("xmlNewDoc failed");
295 /* create the root signature node */
296 sign = xmlSecTmplSignatureCreate(doc, xmlSecTransformInclC14N11Id, xmlSecTransformRsaSha256Id, properties[!!index].id);
298 ERROR("xmlSecTmplSignatureCreate failed");
301 xmlDocSetRootElement(doc, sign);
303 /* create the object and its reference */
304 obj = xmlSecTmplSignatureAddObject(sign, "prop", NULL, NULL);
306 ERROR("xmlSecTmplSignatureAddObject failed");
309 rc = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, properties[!!index].xml, &props);
311 ERROR("xmlParseBalancedChunkMemory failed");
314 if (NULL == xmlAddChild(obj, props)) {
315 ERROR("filling object node failed");
320 /* create references to files */
321 mask = index ? flag_distributor_signature : flag_signature;
323 for (i = 0 ; i < fc ; i++) {
324 fdesc = file_of_index(i);
325 if (fdesc->type == type_file && (fdesc->flags & mask) == 0) {
326 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, fdesc->name, NULL);
328 ERROR("creation of reference to %s failed", fdesc->name);
334 /* create reference to object having properties */
335 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, "#prop", NULL);
337 ERROR("creation of reference to #prop failed");
340 if (NULL == xmlSecTmplReferenceAddTransform(ref, xmlSecTransformInclC14N11Id)) {
341 ERROR("setting transform reference to #prop failed");
345 /* adds the X509 data */
346 kinfo = xmlSecTmplSignatureEnsureKeyInfo(sign, NULL);
348 ERROR("xmlSecTmplSignatureEnsureKeyInfo failed");
351 if (NULL == xmlSecTmplKeyInfoAddX509Data(kinfo)) {
352 ERROR("xmlSecTmplKeyInfoAddX509Data failed");
357 dsigctx = xmlSecDSigCtxCreate(keymgr);
358 if (dsigctx == NULL) {
359 ERROR("xmlSecDSigCtxCreate failed.");
362 dsigctx->signKey = xmlSecCryptoAppKeyLoad(key, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
363 if (dsigctx->signKey == NULL) {
364 ERROR("loading key %s failed.", key);
368 if(xmlSecCryptoAppKeyCertLoad(dsigctx->signKey, *certs, xmlSecKeyDataFormatPem) < 0) {
369 ERROR("loading certificate %s failed.", *certs);
374 if(xmlSecDSigCtxSign(dsigctx, sign) < 0) {
375 ERROR("signing the document failed.");
378 xmlSecDSigCtxDestroy(dsigctx);
382 xmlSecDSigCtxDestroy(dsigctx);