c3cd9bbbfa1f23277913f415c8f3a9551a9b7998
[shibboleth/cpp-xmltooling.git] / xmltoolingtest / SignatureTest.h
1 /*\r
2  *  Copyright 2001-2005 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 #include "XMLObjectBaseTestCase.h"\r
18 \r
19 #include <xmltooling/signature/SignatureValidator.h>\r
20 \r
21 #include <fstream>\r
22 #include <openssl/pem.h>\r
23 #include <xercesc/util/XMLUniDefs.hpp>\r
24 #include <xsec/dsig/DSIGReference.hpp>\r
25 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>\r
26 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
27 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
28 #include <xsec/enc/XSECCryptoException.hpp>\r
29 #include <xsec/framework/XSECException.hpp>\r
30 \r
31 class TestContext : public ContentReference\r
32 {\r
33     XMLCh* m_uri;\r
34     \r
35 public:\r
36     TestContext(const XMLCh* uri) {\r
37         m_uri=XMLString::replicate(uri);\r
38     }\r
39     \r
40     virtual ~TestContext() {\r
41         XMLString::release(&m_uri);\r
42     }\r
43 \r
44     void createReferences(DSIGSignature* sig) {\r
45         DSIGReference* ref=sig->createReference(m_uri);\r
46         ref->appendEnvelopedSignatureTransform();\r
47         ref->appendCanonicalizationTransform(CANON_C14NE_NOC);\r
48     }\r
49 };\r
50 \r
51 class TestValidator : public SignatureValidator\r
52 {\r
53     XMLCh* m_uri;\r
54     \r
55     TestValidator(const TestValidator& src) : SignatureValidator(src) {\r
56         m_uri=XMLString::replicate(src.m_uri);\r
57     }\r
58 \r
59 public:\r
60     TestValidator(const XMLCh* uri, XSECCryptoKey* key) : SignatureValidator(key) {\r
61         m_uri=XMLString::replicate(uri);\r
62     }\r
63     \r
64     virtual ~TestValidator() {\r
65         XMLString::release(&m_uri);\r
66     }\r
67 \r
68     TestValidator* clone() const {\r
69         return new TestValidator(*this);\r
70     }\r
71 \r
72     void validate(const Signature* sigObj) const {\r
73         DSIGSignature* sig=sigObj->getXMLSignature();\r
74         if (!sig)\r
75             throw SignatureException("Only a marshalled Signature object can be verified.");\r
76         const XMLCh* uri=sig->getReferenceList()->item(0)->getURI();\r
77         TSM_ASSERT_SAME_DATA("Reference URI does not match.",uri,m_uri,XMLString::stringLen(uri));\r
78         SignatureValidator::validate(sigObj);\r
79     }\r
80 };\r
81 \r
82 class _addcert : public std::binary_function<X509Data*,XSECCryptoX509*,void> {\r
83 public:\r
84     void operator()(X509Data* bag, XSECCryptoX509* cert) const {\r
85         safeBuffer& buf=cert->getDEREncodingSB();\r
86         X509Certificate* x=X509CertificateBuilder::buildX509Certificate();\r
87         x->setValue(buf.sbStrToXMLCh());\r
88         bag->getX509Certificates().push_back(x);\r
89     }\r
90 };\r
91 \r
92 class SignatureTest : public CxxTest::TestSuite {\r
93     XSECCryptoKey* m_key;\r
94     vector<XSECCryptoX509*> m_certs;\r
95 public:\r
96     void setUp() {\r
97         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
98         QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME);\r
99         XMLObjectBuilder::registerBuilder(qname, new SimpleXMLObjectBuilder());\r
100         XMLObjectBuilder::registerBuilder(qtype, new SimpleXMLObjectBuilder());\r
101         string keypath=data_path + "key.pem";\r
102         BIO* in=BIO_new(BIO_s_file_internal());\r
103         if (in && BIO_read_filename(in,keypath.c_str())>0) {\r
104             EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);\r
105             if (pkey) {\r
106                 m_key=new OpenSSLCryptoKeyRSA(pkey);\r
107                 EVP_PKEY_free(pkey);\r
108             }\r
109         }\r
110         if (in) BIO_free(in);\r
111         TS_ASSERT(m_key!=NULL);\r
112 \r
113         string certpath=data_path + "cert.pem";\r
114         in=BIO_new(BIO_s_file_internal());\r
115         if (in && BIO_read_filename(in,certpath.c_str())>0) {\r
116             X509* x=NULL;\r
117             while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) {\r
118                 m_certs.push_back(new OpenSSLCryptoX509(x));\r
119                 X509_free(x);\r
120             }\r
121         }\r
122         if (in) BIO_free(in);\r
123         TS_ASSERT(m_certs.size()>0);\r
124         \r
125     }\r
126 \r
127     void tearDown() {\r
128         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
129         QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME);\r
130         XMLObjectBuilder::deregisterBuilder(qname);\r
131         XMLObjectBuilder::deregisterBuilder(qtype);\r
132         delete m_key;\r
133         for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
134     }\r
135 \r
136     void testSignature() {\r
137         TS_TRACE("testSignature");\r
138 \r
139         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
140         const SimpleXMLObjectBuilder* b=dynamic_cast<const SimpleXMLObjectBuilder*>(XMLObjectBuilder::getBuilder(qname));\r
141         TS_ASSERT(b!=NULL);\r
142         \r
143         auto_ptr<SimpleXMLObject> sxObject(b->buildObject());\r
144         TS_ASSERT(sxObject.get()!=NULL);\r
145         VectorOf(SimpleXMLObject) kids=sxObject->getSimpleXMLObjects();\r
146         kids.push_back(b->buildObject());\r
147         kids.push_back(b->buildObject());\r
148         \r
149         // Test some collection stuff\r
150         auto_ptr_XMLCh foo("Foo");\r
151         auto_ptr_XMLCh bar("Bar");\r
152         kids.begin()->setId(foo.get());\r
153         kids[1]->setValue(bar.get());\r
154         \r
155         // Append a Signature.\r
156         Signature* sig=SignatureBuilder::buildSignature();\r
157         sxObject->setSignature(sig);\r
158         sig->setContentReference(new TestContext(&chNull));\r
159         sig->setSigningKey(m_key->clone());\r
160         \r
161         // Build KeyInfo.\r
162         KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();\r
163         X509Data* x509Data=X509DataBuilder::buildX509Data();\r
164         keyInfo->getX509Datas().push_back(x509Data);\r
165         for_each(m_certs.begin(),m_certs.end(),bind1st(_addcert(),x509Data));\r
166         sig->setKeyInfo(keyInfo);\r
167         \r
168         // Signing context for the whole document.\r
169         vector<Signature*> sigs(1,sig);\r
170         DOMElement* rootElement = NULL;\r
171         try {\r
172             rootElement=sxObject->marshall((DOMDocument*)NULL,&sigs);\r
173         }\r
174         catch (XMLToolingException& e) {\r
175             TS_TRACE(e.what());\r
176             throw;\r
177         }\r
178         \r
179         string buf;\r
180         XMLHelper::serialize(rootElement, buf);\r
181         //TS_TRACE(buf.c_str());\r
182 \r
183         istringstream in(buf);\r
184         DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
185         auto_ptr<SimpleXMLObject> sxObject2(dynamic_cast<SimpleXMLObject*>(b->buildFromDocument(doc)));\r
186         TS_ASSERT(sxObject2.get()!=NULL);\r
187         TS_ASSERT(sxObject2->getSignature()!=NULL);\r
188         sxObject2->getSignature()->registerValidator(new TestValidator(&chNull,m_key->clone()));\r
189         \r
190         try {\r
191             sxObject2->getSignature()->validate(false);\r
192         }\r
193         catch (XMLToolingException& e) {\r
194             TS_TRACE(e.what());\r
195             throw;\r
196         }\r
197     }\r
198 \r
199 };\r