Merge branch '1.x' of ssh://authdev.it.ohio-state.edu/~scantor/git/cpp-xmltooling...
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / CredentialCriteria.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  * CredentialCriteria.cpp
23  *
24  * Class for specifying criteria by which a CredentialResolver should resolve credentials.
25  */
26
27 #include "internal.h"
28 #include "logging.h"
29 #include "XMLToolingConfig.h"
30 #include "security/X509Credential.h"
31 #include "security/CredentialCriteria.h"
32 #include "security/KeyInfoResolver.h"
33 #include "security/SecurityHelper.h"
34 #include "signature/Signature.h"
35
36 #include <openssl/dsa.h>
37 #include <openssl/rsa.h>
38 #include <xsec/dsig/DSIGKeyInfoList.hpp>
39 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
40 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
41
42 using xmlsignature::KeyInfo;
43 using xmlsignature::Signature;
44 using namespace xmltooling::logging;
45 using namespace xmltooling;
46 using namespace std;
47
48 CredentialCriteria::CredentialCriteria()
49     : m_keyUsage(Credential::UNSPECIFIED_CREDENTIAL), m_keySize(0), m_maxKeySize(0), m_key(nullptr),
50         m_keyInfo(nullptr), m_nativeKeyInfo(nullptr), m_credential(nullptr)
51 {
52 }
53
54 CredentialCriteria::~CredentialCriteria()
55 {
56     delete m_credential;
57 }
58
59 unsigned int CredentialCriteria::getUsage() const
60 {
61     return m_keyUsage;
62 }
63
64 void CredentialCriteria::setUsage(unsigned int usage)
65 {
66     m_keyUsage = usage;
67 }
68
69 const char* CredentialCriteria::getPeerName() const
70 {
71     return m_peerName.empty() ? nullptr : m_peerName.c_str();
72 }
73
74 void CredentialCriteria::setPeerName(const char* peerName)
75 {
76     m_peerName.erase();
77     if (peerName)
78         m_peerName = peerName;
79 }
80
81 const char* CredentialCriteria::getKeyAlgorithm() const
82 {
83     return m_keyAlgorithm.empty() ? nullptr : m_keyAlgorithm.c_str();
84 }
85
86 void CredentialCriteria::setKeyAlgorithm(const char* keyAlgorithm)
87 {
88     m_keyAlgorithm.erase();
89     if (keyAlgorithm)
90         m_keyAlgorithm = keyAlgorithm;
91 }
92
93 unsigned int CredentialCriteria::getKeySize() const
94 {
95     return m_keySize;
96 }
97
98 void CredentialCriteria::setKeySize(unsigned int keySize)
99 {
100     m_keySize = keySize;
101 }
102
103 unsigned int CredentialCriteria::getMaxKeySize() const
104 {
105     return m_maxKeySize;
106 }
107
108 void CredentialCriteria::setMaxKeySize(unsigned int keySize)
109 {
110     m_maxKeySize = keySize;
111 }
112
113 void CredentialCriteria::setXMLAlgorithm(const XMLCh* algorithm)
114 {
115     if (algorithm) {
116         pair<const char*,unsigned int> mapped = XMLToolingConfig::getConfig().mapXMLAlgorithmToKeyAlgorithm(algorithm);
117         setKeyAlgorithm(mapped.first);
118         setKeySize(mapped.second);
119     }
120     else {
121         setKeyAlgorithm(nullptr);
122         setKeySize(0);
123     }
124 }
125
126 const set<string>& CredentialCriteria::getKeyNames() const
127 {
128     return m_keyNames;
129 }
130
131 set<string>& CredentialCriteria::getKeyNames()
132 {
133     return m_keyNames;
134 }
135
136 XSECCryptoKey* CredentialCriteria::getPublicKey() const
137 {
138     return m_key;
139 }
140
141 void CredentialCriteria::setPublicKey(XSECCryptoKey* key)
142 {
143     m_key = key;
144 }
145
146 const KeyInfo* CredentialCriteria::getKeyInfo() const
147 {
148     return m_keyInfo;
149 }
150
151 void CredentialCriteria::setKeyInfo(const KeyInfo* keyInfo, int extraction)
152 {
153     delete m_credential;
154     m_credential = nullptr;
155     m_keyInfo = keyInfo;
156     if (!keyInfo || !extraction)
157         return;
158
159     int types = (extraction & KEYINFO_EXTRACTION_KEY) ? Credential::RESOLVE_KEYS : 0;
160     types |= (extraction & KEYINFO_EXTRACTION_KEYNAMES) ? X509Credential::RESOLVE_CERTS : 0;
161     m_credential = XMLToolingConfig::getConfig().getKeyInfoResolver()->resolve(keyInfo,types);
162
163     // Ensure any key names have been sucked out for later if desired.
164     if (extraction & KEYINFO_EXTRACTION_KEYNAMES) {
165         X509Credential* xcred = dynamic_cast<X509Credential*>(m_credential);
166         if (xcred)
167             xcred->extract();
168     }
169 }
170
171 DSIGKeyInfoList* CredentialCriteria::getNativeKeyInfo() const
172 {
173     return m_nativeKeyInfo;
174 }
175
176 void CredentialCriteria::setNativeKeyInfo(DSIGKeyInfoList* keyInfo, int extraction)
177 {
178     delete m_credential;
179     m_credential = nullptr;
180     m_nativeKeyInfo = keyInfo;
181     if (!keyInfo || !extraction)
182         return;
183
184     int types = (extraction & KEYINFO_EXTRACTION_KEY) ? Credential::RESOLVE_KEYS : 0;
185     types |= (extraction & KEYINFO_EXTRACTION_KEYNAMES) ? X509Credential::RESOLVE_CERTS : 0;
186     m_credential = XMLToolingConfig::getConfig().getKeyInfoResolver()->resolve(keyInfo,types);
187
188     // Ensure any key names have been sucked out for later if desired.
189     if (extraction & KEYINFO_EXTRACTION_KEYNAMES) {
190         X509Credential* xcred = dynamic_cast<X509Credential*>(m_credential);
191         if (xcred)
192             xcred->extract();
193     }
194 }
195
196 void CredentialCriteria::setSignature(const Signature& sig, int extraction)
197 {
198     setXMLAlgorithm(sig.getSignatureAlgorithm());
199     KeyInfo* k = sig.getKeyInfo();
200     if (k)
201         return setKeyInfo(k, extraction);
202     DSIGSignature* dsig = sig.getXMLSignature();
203     if (dsig)
204         setNativeKeyInfo(dsig->getKeyInfoList(), extraction);
205 }
206
207 void CredentialCriteria::reset()
208 {
209     setUsage(Credential::UNSPECIFIED_CREDENTIAL);
210     setKeySize(0);
211     setMaxKeySize(0);
212     setKeyAlgorithm(nullptr);
213     getKeyNames().clear();
214     setKeyInfo(nullptr);
215     setNativeKeyInfo(nullptr);
216 }
217
218 bool CredentialCriteria::matches(const Credential& credential) const
219 {
220     Category& log = Category::getInstance(XMLTOOLING_LOGCAT".CredentialCriteria");
221
222     // Usage check, if specified and we have one, compare masks.
223     if (getUsage() != Credential::UNSPECIFIED_CREDENTIAL) {
224         if (credential.getUsage() != Credential::UNSPECIFIED_CREDENTIAL)
225             if ((getUsage() & credential.getUsage()) == 0) {
226                 if (log.isDebugEnabled())
227                     log.debug("usage didn't match (%u != %u)", getUsage(), credential.getUsage());
228                 return false;
229             }
230     }
231
232     // Algorithm check, if specified and we have one.
233     const char* alg = getKeyAlgorithm();
234     if (alg && *alg) {
235         const char* alg2 = credential.getAlgorithm();
236         if (alg2 && *alg2) {
237             if (strcmp(alg,alg2)) {
238                 if (log.isDebugEnabled())
239                     log.debug("key algorithm didn't match ('%s' != '%s')", getKeyAlgorithm(), credential.getAlgorithm());
240                 return false;
241             }
242         }
243     }
244
245     // KeySize check, if specified and we have one.
246     unsigned int ksize = credential.getKeySize();
247     if (ksize > 0) {
248         if (m_keySize > 0 && m_maxKeySize == 0) {
249             if (ksize != m_keySize) {
250                 log.debug("key size (%u) didn't match (%u)", ksize, m_keySize);
251                 return false;
252             }
253         }
254         else if (m_keySize > 0 && ksize < m_keySize) {
255             log.debug("key size (%u) smaller than minimum (%u)", ksize, m_keySize);
256             return false;
257         }
258         else if (m_maxKeySize > 0 && ksize > m_maxKeySize) {
259             log.debug("key size (%u) larger than maximum (%u)", ksize, m_maxKeySize);
260             return false;
261         }
262     }
263
264     // See if we can test key names.
265     set<string> critnames = getKeyNames();
266     if (m_credential)
267         critnames.insert(m_credential->getKeyNames().begin(), m_credential->getKeyNames().end());
268     const set<string>& crednames = credential.getKeyNames();
269     if (!critnames.empty() && !crednames.empty()) {
270         bool found = false;
271         for (set<string>::const_iterator n = critnames.begin(); n!=critnames.end(); ++n) {
272             if (crednames.count(*n)>0) {
273                 found = true;
274                 break;
275             }
276         }
277         if (!found) {
278             log.debug("credential name(s) didn't overlap");
279             return false;
280         }
281     }
282
283     // See if we have to match a specific key.
284     const XSECCryptoKey* key1 = getPublicKey();
285     if (!key1 && m_credential)
286         key1 = m_credential->getPublicKey();
287     if (!key1)
288         return true;    // no key to compare against, so we're done
289
290     const XSECCryptoKey* key2 = credential.getPublicKey();
291     if (!key2)
292         return true;   // no key here, so we can't test it
293
294     if (SecurityHelper::matches(*key1, *key2))
295         return true;
296     
297     log.debug("keys didn't match");
298     return false;
299 }