/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// set intended operation to sign - several asserts inside libxmlsec // wanting that for digest / transforms
pDsigCtx->operation = xmlSecTransformOperationSign;
// we default to SHA512 for all digests - nss crypto does not have it... //pDsigCtx->defDigestMethodId = xmlSecTransformSha512Id;
// Calculate digest for all references
xmlNodePtr cur = xmlSecGetNextElementNode(pNode->children); if( cur != nullptr )
cur = xmlSecGetNextElementNode(cur->children); while( cur != nullptr )
{ // some of those children I suppose should be reference elements if( xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs) )
{
xmlSecDSigReferenceCtxPtr pDsigRefCtx =
xmlSecDSigReferenceCtxCreate(pDsigCtx,
xmlSecDSigReferenceOriginSignedInfo); if(pDsigRefCtx == nullptr) throw RuntimeException();
// add this one to the list if( xmlSecPtrListAdd(&(pDsigCtx->signedInfoReferences),
pDsigRefCtx) < 0 )
{ // TODO resource handling
xmlSecDSigReferenceCtxDestroy(pDsigRefCtx); throw RuntimeException();
}
// final check - all good? if(pDsigRefCtx->status != xmlSecDSigStatusSucceeded)
{
pDsigCtx->status = xmlSecDSigStatusInvalid; return aTemplate; // TODO - harder error?
}
}
cur = xmlSecGetNextElementNode(cur->next);
}
// get me a digestible buffer from the signature template! // -------------------------------------------------------
// run the transformations over SignedInfo element (first child of // pNode)
xmlSecNodeSetPtr nodeset = nullptr;
cur = xmlSecGetNextElementNode(pNode->children); // TODO assert that...
nodeset = xmlSecNodeSetGetChildren(pNode->doc, cur, 1, 0); if(nodeset == nullptr) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
if( xmlSecTransformCtxXmlExecute(&(pDsigCtx->transformCtx), nodeset) < 0 ) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// now extract the keyid from PGPData // walk xml tree to PGPData node - go to children, first is // SignedInfo, 2nd is signaturevalue, 3rd is KeyInfo // 1st child is PGPData, 1st grandchild is PGPKeyID
cur = xmlSecGetNextElementNode(pNode->children); // TODO error handling
cur = xmlSecGetNextElementNode(cur->next);
cur = xmlSecGetNextElementNode(cur->next);
cur = xmlSecGetNextElementNode(cur->children); // check that this is now PGPData if(!xmlSecCheckNodeName(cur, xmlSecNodePGPData, xmlSecDSigNs)) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); // check that this is now PGPKeyID
cur = xmlSecGetNextElementNode(cur->children); staticconst xmlChar xmlSecNodePGPKeyID[] = "PGPKeyID"; if(!xmlSecCheckNodeName(cur, xmlSecNodePGPKeyID, xmlSecDSigNs)) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
GpgME::Context& rCtx=pSecEnv->getGpgContext();
rCtx.setKeyListMode(GPGME_KEYLIST_MODE_LOCAL);
GpgME::Error err;
xmlChar* pKey=xmlNodeGetContent(cur);
xmlSecSize nWritten; int nRet = xmlSecBase64Decode_ex(pKey, reinterpret_cast<xmlSecByte*>(pKey), xmlStrlen(pKey), &nWritten); if(nRet < 0) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
rCtx.clearSigningKeys(); // tdf#108828 Clear keys from previous unsuccessful sessions if( rCtx.addSigningKey(
rCtx.key( reinterpret_cast<char*>(pKey), err, true)) ) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
xmlFree(pKey);
// good, ctx is setup now, let's sign the lot
GpgME::Data data_in( reinterpret_cast<char*>(xmlSecBufferGetData(pDsigCtx->transformCtx.result)),
xmlSecBufferGetSize(pDsigCtx->transformCtx.result), false);
GpgME::Data data_out;
// we base64-encode anyway
rCtx.setArmor(false);
GpgME::SigningResult sign_res=rCtx.sign(data_in, data_out,
GpgME::Detached);
off_t result = data_out.seek(0,SEEK_SET);
(void) result;
assert(result == 0); int len=0, curr=0; char buf; while( (curr=data_out.read(&buf, 1)) )
len += curr;
if(sign_res.error() || !len) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// write signed data to xml
xmlChar* signature = static_cast<xmlChar*>(xmlMalloc(len + 1)); if(signature == nullptr) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
result = data_out.seek(0,SEEK_SET);
assert(result == 0); if( data_out.read(signature, len) != len ) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// conversion to base64
xmlChar* signatureEncoded=nullptr; if( !(signatureEncoded=xmlSecBase64Encode(reinterpret_cast<xmlSecByte*>(signature), len, 79)) ) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
xmlFree(signature);
// walk xml tree to sign value node - go to children, first is // SignedInfo, 2nd is signaturevalue
cur = xmlSecGetNextElementNode(pNode->children);
cur = xmlSecGetNextElementNode(cur->next);
// TODO some assert would be good...
xmlNodeSetContentLen(cur, signatureEncoded, xmlStrlen(signatureEncoded));
xmlFree(signatureEncoded);
// set intended operation to verify - several asserts inside libxmlsec // wanting that for digest / transforms
pDsigCtx->operation = xmlSecTransformOperationVerify;
// reset status - to be set later
pDsigCtx->status = xmlSecDSigStatusUnknown;
// get me a digestible buffer from the SignatureInfo node! // -------------------------------------------------------
// run the transformations - first child node is required to // be SignatureInfo
xmlSecNodeSetPtr nodeset = nullptr;
xmlNodePtr cur = xmlSecGetNextElementNode(pNode->children); // TODO assert that...
nodeset = xmlSecNodeSetGetChildren(pNode->doc, cur, 1, 0); if(nodeset == nullptr) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// TODO assert we really have the SignatureInfo here? if( xmlSecTransformCtxXmlExecute(&(pDsigCtx->transformCtx), nodeset) < 0 ) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// Validate the template via gpgme
GpgME::Context& rCtx=pSecEnv->getGpgContext();
// walk xml tree to sign value node - go to children, first is // SignedInfo, 2nd is signaturevalue
cur = xmlSecGetNextElementNode(pNode->children);
cur = xmlSecGetNextElementNode(cur->next);
if(!xmlSecCheckNodeName(cur, xmlSecNodeSignatureValue, xmlSecDSigNs)) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
xmlChar* pSignatureValue=xmlNodeGetContent(cur);
xmlSecSize nSigSize; int nRet = xmlSecBase64Decode_ex(pSignatureValue, reinterpret_cast<xmlSecByte*>(pSignatureValue), xmlStrlen(pSignatureValue), &nSigSize); if( nRet < 0) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// TODO: needs some more error handling, needs checking _all_ signatures if( verify_res.isNull() || verify_res.numSignatures() == 0 // there is at least 1 signature and it is anything else than fully valid
|| ( (verify_res.numSignatures() > 0)
&& verify_res.signature(0).status().encodedError() > 0 ) )
{ // let's try again, but this time import the public key // payload (avoiding that in a first cut for being a bit // speedier. also prevents all too easy poisoning/sha1 // fingerprint collision attacks)
// walk xml tree to PGPData node - go to children, first is // SignedInfo, 2nd is signaturevalue, 3rd is KeyInfo // 1st child is PGPData, 1st or 2nd grandchild is PGPKeyPacket
cur = xmlSecGetNextElementNode(pNode->children); // TODO error handling
cur = xmlSecGetNextElementNode(cur->next);
cur = xmlSecGetNextElementNode(cur->next);
cur = xmlSecGetNextElementNode(cur->children); // check that this is now PGPData if(!xmlSecCheckNodeName(cur, xmlSecNodePGPData, xmlSecDSigNs)) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); // check that this is now PGPKeyPacket
cur = xmlSecGetNextElementNode(cur->children); staticconst xmlChar xmlSecNodePGPKeyPacket[] = "PGPKeyPacket"; if(!xmlSecCheckNodeName(cur, xmlSecNodePGPKeyPacket, xmlSecDSigNs))
{ // not this one, maybe the next?
cur = xmlSecGetNextElementNode(cur->next); if(!xmlSecCheckNodeName(cur, xmlSecNodePGPKeyPacket, xmlSecDSigNs))
{ // ok, giving up
clearErrorRecorder();
xmlFree(pSignatureValue);
return aTemplate;
}
}
// got a key packet, import & re-validate
xmlChar* pKeyPacket=xmlNodeGetContent(cur);
xmlSecSize nKeyLen;
nRet = xmlSecBase64Decode_ex(pKeyPacket, reinterpret_cast<xmlSecByte*>(pKeyPacket), xmlStrlen(pKeyPacket), &nKeyLen); if( nRet < 0) throw RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr);
// and re-run (rewind text and signature streams to position 0)
(void)data_text.seek(0,SEEK_SET);
(void)data_signature.seek(0,SEEK_SET);
verify_res=rCtx.verifyDetachedSignature(data_signature, data_text);
// TODO: needs some more error handling, needs checking _all_ signatures if( verify_res.isNull() || verify_res.numSignatures() == 0 // there is at least 1 signature and it is anything else than valid
|| ( (verify_res.numSignatures() > 0)
&& verify_res.signature(0).status().encodedError() > 0 ) )
{
clearErrorRecorder();
xmlFree(pSignatureValue);
return aTemplate;
}
}
xmlFree(pSignatureValue);
// now verify digest for all references
cur = xmlSecGetNextElementNode(pNode->children); if( cur != nullptr )
cur = xmlSecGetNextElementNode(cur->children); while( cur != nullptr )
{ // some of those children I suppose should be reference elements if( xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs) )
{
xmlSecDSigReferenceCtxPtr pDsigRefCtx =
xmlSecDSigReferenceCtxCreate(pDsigCtx,
xmlSecDSigReferenceOriginSignedInfo); if(pDsigRefCtx == nullptr) throw RuntimeException();
// add this one to the list if( xmlSecPtrListAdd(&(pDsigCtx->signedInfoReferences),
pDsigRefCtx) < 0 )
{ // TODO resource handling
xmlSecDSigReferenceCtxDestroy(pDsigRefCtx); throw RuntimeException();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.