SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-opensaml.git] / saml / signature / SignatureProfileValidator.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * SignatureProfileValidator.cpp
23  * 
24  * SAML-specific signature verification.
25  */
26  
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "signature/SignableObject.h"
30 #include "signature/SignatureProfileValidator.h"
31
32 #include <xmltooling/logging.h>
33 #include <xmltooling/signature/Signature.h>
34
35 #include <xercesc/util/XMLUniDefs.hpp>
36 #include <xsec/dsig/DSIGReference.hpp>
37 #include <xsec/dsig/DSIGSignature.hpp>
38 #include <xsec/dsig/DSIGTransformList.hpp>
39
40 using namespace opensaml;
41 using namespace xmlsignature;
42 using namespace xmltooling::logging;
43 using namespace xmltooling;
44 using namespace std;
45
46 SignatureProfileValidator::SignatureProfileValidator()
47 {
48 }
49
50 SignatureProfileValidator::~SignatureProfileValidator()
51 {
52 }
53
54 void SignatureProfileValidator::validate(const XMLObject* xmlObject) const
55 {
56     const Signature* sigObj=dynamic_cast<const Signature*>(xmlObject);
57     if (!sigObj)
58         throw ValidationException("Validator only applies to Signature objects.");
59     validateSignature(*sigObj);
60 }
61
62 void SignatureProfileValidator::validateSignature(const Signature& sigObj) const
63 {
64     DSIGSignature* sig=sigObj.getXMLSignature();
65     if (!sig)
66         throw ValidationException("Signature does not exist yet.");
67
68     const SignableObject* signableObj=dynamic_cast<const SignableObject*>(sigObj.getParent());
69     if (!signableObj)
70         throw ValidationException("Signature is not a child of a signable SAML object.");
71
72     if (sig->getObjectLength() != 0) {
73         Category::getInstance(SAML_LOGCAT ".SignatureProfileValidator").error("signature contained an embedded <Object> element");
74         throw ValidationException("Invalid signature profile for SAML object.");
75     }
76
77     sig->setIdByAttributeName(false);
78
79     bool valid=false;
80     DSIGReferenceList* refs=sig->getReferenceList();
81     if (refs && refs->getSize()==1) {
82         DSIGReference* ref=refs->item(0);
83         if (ref) {
84             const XMLCh* URI=ref->getURI();
85             const XMLCh* ID=signableObj->getXMLID();
86             if (URI==nullptr || *URI==0 || (*URI==chPound && ID && !XMLString::compareString(URI+1,ID))) {
87                 DSIGTransformList* tlist=ref->getTransforms();
88                 if (tlist->getSize() <= 2) { 
89                     for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
90                         if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
91                             valid=true;
92                         else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
93                                  tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
94                             valid=false;
95                             Category::getInstance(SAML_LOGCAT ".SignatureProfileValidator").error("signature contained an invalid transform");
96                             break;
97                         }
98                     }
99                 }
100
101                 if (valid && URI && *URI) {
102                     valid = false;
103                     if (sigObj.getDOM() && signableObj->getDOM()) {
104                         DOMElement* signedNode = sigObj.getDOM()->getOwnerDocument()->getElementById(ID);
105                         if (signedNode && signedNode->isSameNode(signableObj->getDOM())) {
106                             valid = true;
107                         }
108                         else {
109                             Category::getInstance(SAML_LOGCAT ".SignatureProfileValidator").error("signature reference does not match parent object node");
110                         }
111                     }
112                 }
113             }
114             else {
115                 Category::getInstance(SAML_LOGCAT ".SignatureProfileValidator").error("signature reference does not match parent object ID");
116             }
117         }
118     }
119     else {
120         Category::getInstance(SAML_LOGCAT ".SignatureProfileValidator").error("signature contained multiple or zero references");
121     }
122     
123     if (!valid)
124         throw ValidationException("Invalid signature profile for SAML object.");
125 }