Integrated credential resolver API with signing context.
[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 <fstream>\r
20 #include <openssl/pem.h>\r
21 #include <xercesc/util/XMLUniDefs.hpp>\r
22 #include <xsec/dsig/DSIGReference.hpp>\r
23 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>\r
24 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
25 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
26 \r
27 class TestContext : public SigningContext, public VerifyingContext, CredentialResolver\r
28 {\r
29     XSECCryptoKey* m_key;\r
30     vector<XSECCryptoX509*> m_certs;\r
31     XMLCh* m_uri;\r
32     \r
33 public:\r
34     TestContext(const XMLCh* uri) {\r
35         string keypath=data_path + "key.pem";\r
36         BIO* in=BIO_new(BIO_s_file_internal());\r
37         if (in && BIO_read_filename(in,keypath.c_str())>0) {\r
38             EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);\r
39             if (pkey) {\r
40                 m_key=new OpenSSLCryptoKeyRSA(pkey);\r
41                 EVP_PKEY_free(pkey);\r
42             }\r
43         }\r
44         if (in) BIO_free(in);\r
45         TS_ASSERT(m_key!=NULL);\r
46 \r
47         string certpath=data_path + "cert.pem";\r
48         in=BIO_new(BIO_s_file_internal());\r
49         if (in && BIO_read_filename(in,certpath.c_str())>0) {\r
50             X509* x=NULL;\r
51             while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) {\r
52                 m_certs.push_back(new OpenSSLCryptoX509(x));\r
53                 X509_free(x);\r
54             }\r
55         }\r
56         if (in) BIO_free(in);\r
57         TS_ASSERT(m_certs.size()>0);\r
58         \r
59         m_uri=XMLString::replicate(uri);\r
60     }\r
61     \r
62     virtual ~TestContext() {\r
63         delete m_key;\r
64         for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
65         XMLString::release(&m_uri);\r
66     }\r
67 \r
68     bool createSignature(DSIGSignature* sig) {\r
69         DSIGReference* ref=sig->createReference(m_uri);\r
70         ref->appendEnvelopedSignatureTransform();\r
71         ref->appendCanonicalizationTransform(CANON_C14NE_NOC);\r
72         return false;\r
73     }\r
74 \r
75     void verifySignature(DSIGSignature* sig) const {\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         XSECKeyInfoResolverDefault resolver;\r
79         sig->setKeyInfoResolver(&resolver); // It will clone the resolver for us.\r
80         sig->verify();\r
81     }\r
82     \r
83     KeyInfo* getKeyInfo() { return NULL; }\r
84     CredentialResolver& getCredentialResolver() { return *this; }\r
85     const char* getId() const { return "test"; }\r
86     const std::vector<XSECCryptoX509*>* getX509Certificates() { return &m_certs; }\r
87     XSECCryptoKey* getPublicKey() { return m_key; }\r
88     XSECCryptoKey* getPrivateKey() { return m_key; }\r
89     Lockable& lock() { return *this; }\r
90     void unlock() {}\r
91 };\r
92 \r
93 class SignatureTest : public CxxTest::TestSuite {\r
94 public:\r
95     void setUp() {\r
96         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
97         QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME);\r
98         XMLObjectBuilder::registerBuilder(qname, new SimpleXMLObjectBuilder());\r
99         XMLObjectBuilder::registerBuilder(qtype, new SimpleXMLObjectBuilder());\r
100     }\r
101 \r
102     void tearDown() {\r
103         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
104         QName qtype(SimpleXMLObject::NAMESPACE,SimpleXMLObject::TYPE_NAME);\r
105         XMLObjectBuilder::deregisterBuilder(qname);\r
106         XMLObjectBuilder::deregisterBuilder(qtype);\r
107     }\r
108 \r
109     void testSignature() {\r
110         TS_TRACE("testSignature");\r
111 \r
112         QName qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME);\r
113         const SimpleXMLObjectBuilder* b=dynamic_cast<const SimpleXMLObjectBuilder*>(XMLObjectBuilder::getBuilder(qname));\r
114         TS_ASSERT(b!=NULL);\r
115         \r
116         auto_ptr<SimpleXMLObject> sxObject(b->buildObject());\r
117         TS_ASSERT(sxObject.get()!=NULL);\r
118         VectorOf(SimpleXMLObject) kids=sxObject->getSimpleXMLObjects();\r
119         kids.push_back(b->buildObject());\r
120         kids.push_back(b->buildObject());\r
121         \r
122         // Test some collection stuff\r
123         auto_ptr_XMLCh foo("Foo");\r
124         auto_ptr_XMLCh bar("Bar");\r
125         kids.begin()->setId(foo.get());\r
126         kids[1]->setValue(bar.get());\r
127         \r
128         // Append a Signature.\r
129         Signature* sig=SignatureBuilder::newSignature();\r
130         sxObject->setSignature(sig);\r
131         \r
132         // Signing context for the whole document.\r
133         TestContext tc(&chNull);\r
134         MarshallingContext mctx(sig,&tc);\r
135         DOMElement* rootElement = sxObject->marshall((DOMDocument*)NULL,&mctx);\r
136         \r
137         string buf;\r
138         XMLHelper::serialize(rootElement, buf);\r
139         //TS_TRACE(buf.c_str());\r
140 \r
141         istringstream in(buf);\r
142         DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
143         auto_ptr<SimpleXMLObject> sxObject2(dynamic_cast<SimpleXMLObject*>(b->buildFromDocument(doc)));\r
144         TS_ASSERT(sxObject2.get()!=NULL);\r
145         TS_ASSERT(sxObject2->getSignature()!=NULL);\r
146         \r
147         try {\r
148             sxObject2->getSignature()->verify(tc);\r
149         }\r
150         catch (SignatureException& e) {\r
151             TS_TRACE(e.what());\r
152             throw;\r
153         }\r
154     }\r
155 \r
156 };\r