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>
40 static int initstatus;
42 static xmlSecKeysMngrPtr keymgr;
44 static const char trusted_certificates_directory[] = WGTPKG_TRUSTED_CERT_DIR;
46 /* checks if a file match uri (should not be a distributor signature) */
47 static int file_match_cb(const char *uri)
49 struct filedesc *fdesc = file_of_name(uri);
50 return fdesc != NULL && fdesc->type == type_file && (fdesc->flags & flag_distributor_signature) == 0;
53 /* open the file of uri */
54 static void *file_open_cb(const char *file)
56 struct filedesc *fdesc;
60 fdesc = file_of_name(file);
62 ERROR("shouldn't open uri %s", file);
66 fd = openat(workdirfd, file, O_RDONLY);
67 f = fd < 0 ? NULL : fdopen(fd, "r");
69 ERROR("can't open file %s for reading", file);
73 fdesc->flags |= flag_opened;
78 /* read the opened file */
79 static int file_read_cb(void *context, char *buffer, int len)
81 size_t r = fread(buffer, 1, len, (FILE*)context);
82 return r ? (int)r : feof((FILE*)context) ? 0 : - 1;
85 /* close the opened file */
86 static int file_close_cb(void *context)
88 return (int)fclose((FILE*)context);
91 /* echo an error message */
92 static void errors_cb(const char *file, int line, const char *func, const char *errorObject, const char *errorSubject, int reason, const char *msg)
94 ERROR("xmlSec error %3d: %s (subject=\"%s\", object=\"%s\")", reason, msg, errorSubject ? errorSubject : "?", errorObject ? errorObject : "?");
97 /* fills database with trusted keys */
98 static int fill_trusted_keys_file(const char *file)
100 int err = xmlSecCryptoAppKeysMngrCertLoad(keymgr, file, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted);
102 ERROR("xmlSecCryptoAppKeysMngrCertLoadMemory failed for %s", file);
108 /* fills database with trusted keys */
109 static int fill_trusted_keys_dir(const char *directory)
114 char path[PATH_MAX], *e;
116 e = stpcpy(path, directory);
119 ERROR("opendir %s failed in fill_trusted_keys_dir", path);
125 while (ent != NULL) {
126 if (ent->d_type == DT_REG) {
127 strcpy(e, ent->d_name);
128 err = fill_trusted_keys_file(path);
142 /* initialisation of access to xmlsec */
152 if(xmlSecInit() < 0) {
153 ERROR("xmlSecInit failed.");
157 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
158 if(xmlSecCryptoDLLoadLibrary(XMLSEC_CRYPTO) < 0) {
159 ERROR("xmlSecCryptoDLLoadLibrary %s failed.", XMLSEC_CRYPTO);
164 if(xmlSecCryptoAppInit(NULL) < 0) {
165 ERROR("xmlSecCryptoAppInit failed.");
169 if(xmlSecCryptoInit() < 0) {
170 ERROR("xmlSecCryptoInit failed.");
174 xmlSecErrorsSetCallback(errors_cb);
176 xmlSecIOCleanupCallbacks();
177 if (xmlSecIORegisterCallbacks(file_match_cb,
178 file_open_cb, file_read_cb, file_close_cb)) {
179 ERROR("xmlSecIORegisterCallbacks failed.");
183 keymgr = xmlSecKeysMngrCreate();
184 if (keymgr == NULL) {
185 ERROR("xmlSecKeysMngrCreate failed.");
189 if(xmlSecCryptoAppDefaultKeysMngrInit(keymgr) < 0) {
190 ERROR("xmlSecCryptoAppDefaultKeysMngrInit failed.");
193 fill_trusted_keys_dir(trusted_certificates_directory);
200 /* shuting down accesses to xmlsec */
201 void xmlsec_shutdown()
203 xmlSecKeysMngrDestroy(keymgr);
205 xmlSecCryptoShutdown();
207 xmlSecCryptoAppShutdown();
212 /* verify a signature */
213 int xmlsec_verify(xmlNodePtr node)
216 xmlSecDSigCtxPtr dsigctx;
218 assert(initdone && !initstatus);
220 dsigctx = xmlSecDSigCtxCreate(keymgr);
221 if (dsigctx == NULL) {
222 ERROR("xmlSecDSigCtxCreate failed.");
225 rc = xmlSecDSigCtxVerify(dsigctx, node);
227 ERROR("xmlSecDSigCtxVerify failed.");
228 else if (dsigctx->status != xmlSecDSigStatusSucceeded) {
229 ERROR("invalid signature.");
232 xmlSecDSigCtxDestroy(dsigctx);
238 /* templates for properties of signature files */
239 static const struct { const char *id; const char *xml; } properties[2] = {
241 .id = "AuthorSignature", /* template of properties for author signature */
243 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
244 "<SignatureProperty Id=\"profile\" Target=\"#AuthorSignature\">"
245 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
246 "</SignatureProperty>"
247 "<SignatureProperty Id=\"role\" Target=\"#AuthorSignature\">"
248 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-author\"></dsp:Role>"
249 "</SignatureProperty>"
250 "<SignatureProperty Id=\"identifier\" Target=\"#AuthorSignature\">"
251 "<dsp:Identifier></dsp:Identifier>"
252 "</SignatureProperty>"
253 "</SignatureProperties>"
256 .id = "DistributorSignature", /* template of properties for distributor signature */
258 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
259 "<SignatureProperty Id=\"profile\" Target=\"#DistributorSignature\">"
260 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
261 "</SignatureProperty>"
262 "<SignatureProperty Id=\"role\" Target=\"#DistributorSignature\">"
263 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-distributor\"></dsp:Role>"
264 "</SignatureProperty>"
265 "<SignatureProperty Id=\"identifier\" Target=\"#DistributorSignature\">"
266 "<dsp:Identifier></dsp:Identifier>"
267 "</SignatureProperty>"
268 "</SignatureProperties>"
272 /* create a signature of 'index' (0 for author, other values for distributors)
273 using the private 'key' (filename) and the certificates 'certs' (filenames)
275 xmlDocPtr xmlsec_create(int index, const char *key, const char **certs)
277 unsigned int i, fc, mask;
278 struct filedesc *fdesc;
279 xmlNodePtr sign, obj, ref, kinfo, props;
282 xmlSecDSigCtxPtr dsigctx;
284 assert(initdone && !initstatus);
286 /* create the document */
287 doc = xmlNewDoc("1.0");
289 ERROR("xmlNewDoc failed");
293 /* create the root signature node */
294 sign = xmlSecTmplSignatureCreate(doc, xmlSecTransformInclC14N11Id, xmlSecTransformRsaSha256Id, properties[!!index].id);
296 ERROR("xmlSecTmplSignatureCreate failed");
299 xmlDocSetRootElement(doc, sign);
301 /* create the object and its reference */
302 obj = xmlSecTmplSignatureAddObject(sign, "prop", NULL, NULL);
304 ERROR("xmlSecTmplSignatureAddObject failed");
307 rc = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, properties[!!index].xml, &props);
309 ERROR("xmlParseBalancedChunkMemory failed");
312 if (NULL == xmlAddChild(obj, props)) {
313 ERROR("filling object node failed");
318 /* create references to files */
319 mask = index ? flag_distributor_signature : flag_signature;
321 for (i = 0 ; i < fc ; i++) {
322 fdesc = file_of_index(i);
323 if (fdesc->type == type_file && (fdesc->flags & mask) == 0) {
324 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, fdesc->name, NULL);
326 ERROR("creation of reference to %s failed", fdesc->name);
332 /* create reference to object having properties */
333 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, "#prop", NULL);
335 ERROR("creation of reference to #prop failed");
338 if (NULL == xmlSecTmplReferenceAddTransform(ref, xmlSecTransformInclC14N11Id)) {
339 ERROR("setting transform reference to #prop failed");
343 /* adds the X509 data */
344 kinfo = xmlSecTmplSignatureEnsureKeyInfo(sign, NULL);
346 ERROR("xmlSecTmplSignatureEnsureKeyInfo failed");
349 if (NULL == xmlSecTmplKeyInfoAddX509Data(kinfo)) {
350 ERROR("xmlSecTmplKeyInfoAddX509Data failed");
355 dsigctx = xmlSecDSigCtxCreate(keymgr);
356 if (dsigctx == NULL) {
357 ERROR("xmlSecDSigCtxCreate failed.");
360 dsigctx->signKey = xmlSecCryptoAppKeyLoad(key, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
361 if (dsigctx->signKey == NULL) {
362 ERROR("loading key %s failed.", key);
366 if(xmlSecCryptoAppKeyCertLoad(dsigctx->signKey, *certs, xmlSecKeyDataFormatPem) < 0) {
367 ERROR("loading certificate %s failed.", *certs);
372 if(xmlSecDSigCtxSign(dsigctx, sign) < 0) {
373 ERROR("signing the document failed.");
376 xmlSecDSigCtxDestroy(dsigctx);
380 xmlSecDSigCtxDestroy(dsigctx);