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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <libxml/tree.h>
27 #include <xmlsec/xmlsec.h>
28 #include <xmlsec/xmltree.h>
29 #include <xmlsec/xmldsig.h>
30 #include <xmlsec/crypto.h>
31 #include <xmlsec/templates.h>
32 #include <xmlsec/errors.h>
33 #include <xmlsec/io.h>
39 static int initstatus;
41 static xmlSecKeysMngrPtr keymgr;
43 #ifndef CA_ROOT_DIRECTORY
44 #define CA_ROOT_DIRECTORY "./ca-certificates"
47 /* checks if a file match uri (should not be a distributor signature) */
48 static int file_match_cb(const char *uri)
50 struct filedesc *fdesc = file_of_name(uri);
51 return fdesc != NULL && fdesc->type == type_file && (fdesc->flags & flag_distributor_signature) == 0;
54 /* open the file of uri */
55 static void *file_open_cb(const char *file)
57 struct filedesc *fdesc;
61 fdesc = file_of_name(file);
63 ERROR("shouldn't open uri %s", file);
67 fd = openat(workdirfd, file, O_RDONLY);
68 f = fd < 0 ? NULL : fdopen(fd, "r");
70 ERROR("can't open file %s for reading", file);
74 fdesc->flags |= flag_opened;
79 /* read the opened file */
80 static int file_read_cb(void *context, char *buffer, int len)
82 size_t r = fread(buffer, 1, len, (FILE*)context);
83 return r ? (int)r : feof((FILE*)context) ? 0 : - 1;
86 /* close the opened file */
87 static int file_close_cb(void *context)
89 return (int)fclose((FILE*)context);
92 /* echo an error message */
93 static void errors_cb(const char *file, int line, const char *func, const char *errorObject, const char *errorSubject, int reason, const char *msg)
95 ERROR("xmlSec error %3d: %s (subject=\"%s\", object=\"%s\")", reason, msg, errorSubject ? errorSubject : "?", errorObject ? errorObject : "?");
98 /* fills database with trusted keys */
99 static int fill_trusted_keys_file(const char *file)
101 int err = xmlSecCryptoAppKeysMngrCertLoad(keymgr, file, xmlSecKeyDataFormatPem, xmlSecKeyDataTypeTrusted);
103 ERROR("xmlSecCryptoAppKeysMngrCertLoadMemory failed for %s", file);
109 /* fills database with trusted keys */
110 static int fill_trusted_keys_dir(const char *directory)
115 char path[PATH_MAX], *e;
117 e = stpcpy(path, directory);
120 ERROR("opendir %s failed in fill_trusted_keys_dir", path);
126 while (ent != NULL) {
127 if (ent->d_type == DT_REG) {
128 strcpy(e, ent->d_name);
129 err = fill_trusted_keys_file(path);
143 /* initialisation of access to xmlsec */
153 if(xmlSecInit() < 0) {
154 ERROR("xmlSecInit failed.");
158 #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
159 if(xmlSecCryptoDLLoadLibrary(XMLSEC_CRYPTO) < 0) {
160 ERROR("xmlSecCryptoDLLoadLibrary %s failed.", XMLSEC_CRYPTO);
165 if(xmlSecCryptoAppInit(NULL) < 0) {
166 ERROR("xmlSecCryptoAppInit failed.");
170 if(xmlSecCryptoInit() < 0) {
171 ERROR("xmlSecCryptoInit failed.");
175 xmlSecErrorsSetCallback(errors_cb);
177 xmlSecIOCleanupCallbacks();
178 if (xmlSecIORegisterCallbacks(file_match_cb,
179 file_open_cb, file_read_cb, file_close_cb)) {
180 ERROR("xmlSecIORegisterCallbacks failed.");
184 keymgr = xmlSecKeysMngrCreate();
185 if (keymgr == NULL) {
186 ERROR("xmlSecKeysMngrCreate failed.");
190 if(xmlSecCryptoAppDefaultKeysMngrInit(keymgr) < 0) {
191 ERROR("xmlSecCryptoAppDefaultKeysMngrInit failed.");
194 fill_trusted_keys_dir(CA_ROOT_DIRECTORY);
201 /* shuting down accesses to xmlsec */
202 void xmlsec_shutdown()
204 xmlSecKeysMngrDestroy(keymgr);
206 xmlSecCryptoShutdown();
208 xmlSecCryptoAppShutdown();
213 /* verify a signature */
214 int xmlsec_verify(xmlNodePtr node)
217 xmlSecDSigCtxPtr dsigctx;
219 assert(initdone && !initstatus);
221 dsigctx = xmlSecDSigCtxCreate(keymgr);
222 if (dsigctx == NULL) {
223 ERROR("xmlSecDSigCtxCreate failed.");
226 rc = xmlSecDSigCtxVerify(dsigctx, node);
228 ERROR("xmlSecDSigCtxVerify failed.");
229 else if (dsigctx->status != xmlSecDSigStatusSucceeded) {
230 ERROR("invalid signature.");
233 xmlSecDSigCtxDestroy(dsigctx);
239 /* templates for properties of signature files */
240 static const struct { const char *id; const char *xml; } properties[2] = {
242 .id = "AuthorSignature", /* template of properties for author signature */
244 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
245 "<SignatureProperty Id=\"profile\" Target=\"#AuthorSignature\">"
246 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
247 "</SignatureProperty>"
248 "<SignatureProperty Id=\"role\" Target=\"#AuthorSignature\">"
249 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-author\"></dsp:Role>"
250 "</SignatureProperty>"
251 "<SignatureProperty Id=\"identifier\" Target=\"#AuthorSignature\">"
252 "<dsp:Identifier></dsp:Identifier>"
253 "</SignatureProperty>"
254 "</SignatureProperties>"
257 .id = "DistributorSignature", /* template of properties for distributor signature */
259 "<SignatureProperties xmlns:dsp=\"http://www.w3.org/2009/xmldsig-properties\">"
260 "<SignatureProperty Id=\"profile\" Target=\"#DistributorSignature\">"
261 "<dsp:Profile URI=\"http://www.w3.org/ns/widgets-digsig#profile\"></dsp:Profile>"
262 "</SignatureProperty>"
263 "<SignatureProperty Id=\"role\" Target=\"#DistributorSignature\">"
264 "<dsp:Role URI=\"http://www.w3.org/ns/widgets-digsig#role-distributor\"></dsp:Role>"
265 "</SignatureProperty>"
266 "<SignatureProperty Id=\"identifier\" Target=\"#DistributorSignature\">"
267 "<dsp:Identifier></dsp:Identifier>"
268 "</SignatureProperty>"
269 "</SignatureProperties>"
273 /* create a signature of 'index' (0 for author, other values for distributors)
274 using the private 'key' (filename) and the certificates 'certs' (filenames)
276 xmlDocPtr xmlsec_create(int index, const char *key, const char **certs)
278 unsigned int i, fc, mask;
279 struct filedesc *fdesc;
280 xmlNodePtr sign, obj, ref, kinfo, props;
283 xmlSecDSigCtxPtr dsigctx;
285 assert(initdone && !initstatus);
287 /* create the document */
288 doc = xmlNewDoc("1.0");
290 ERROR("xmlNewDoc failed");
294 /* create the root signature node */
295 sign = xmlSecTmplSignatureCreate(doc, xmlSecTransformInclC14N11Id, xmlSecTransformRsaSha256Id, properties[!!index].id);
297 ERROR("xmlSecTmplSignatureCreate failed");
300 xmlDocSetRootElement(doc, sign);
302 /* create the object and its reference */
303 obj = xmlSecTmplSignatureAddObject(sign, "prop", NULL, NULL);
305 ERROR("xmlSecTmplSignatureAddObject failed");
308 rc = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, properties[!!index].xml, &props);
310 ERROR("xmlParseBalancedChunkMemory failed");
313 if (NULL == xmlAddChild(obj, props)) {
314 ERROR("filling object node failed");
319 /* create references to files */
320 mask = index ? flag_distributor_signature : flag_signature;
322 for (i = 0 ; i < fc ; i++) {
323 fdesc = file_of_index(i);
324 if (fdesc->type == type_file && (fdesc->flags & mask) == 0) {
325 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, fdesc->name, NULL);
327 ERROR("creation of reference to %s failed", fdesc->name);
333 /* create reference to object having properties */
334 ref = xmlSecTmplSignatureAddReference(sign, xmlSecTransformSha256Id, NULL, "#prop", NULL);
336 ERROR("creation of reference to #prop failed");
339 if (NULL == xmlSecTmplReferenceAddTransform(ref, xmlSecTransformInclC14N11Id)) {
340 ERROR("setting transform reference to #prop failed");
344 /* adds the X509 data */
345 kinfo = xmlSecTmplSignatureEnsureKeyInfo(sign, NULL);
347 ERROR("xmlSecTmplSignatureEnsureKeyInfo failed");
350 if (NULL == xmlSecTmplKeyInfoAddX509Data(kinfo)) {
351 ERROR("xmlSecTmplKeyInfoAddX509Data failed");
356 dsigctx = xmlSecDSigCtxCreate(keymgr);
357 if (dsigctx == NULL) {
358 ERROR("xmlSecDSigCtxCreate failed.");
361 dsigctx->signKey = xmlSecCryptoAppKeyLoad(key, xmlSecKeyDataFormatPem, NULL, NULL, NULL);
362 if (dsigctx->signKey == NULL) {
363 ERROR("loading key %s failed.", key);
367 if(xmlSecCryptoAppKeyCertLoad(dsigctx->signKey, *certs, xmlSecKeyDataFormatPem) < 0) {
368 ERROR("loading certificate %s failed.", *certs);
373 if(xmlSecDSigCtxSign(dsigctx, sign) < 0) {
374 ERROR("signing the document failed.");
377 xmlSecDSigCtxDestroy(dsigctx);
381 xmlSecDSigCtxDestroy(dsigctx);