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
CredentialCriteria()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
~CredentialCriteria()54 CredentialCriteria::~CredentialCriteria()
55 {
56 delete m_credential;
57 }
58
getUsage() const59 unsigned int CredentialCriteria::getUsage() const
60 {
61 return m_keyUsage;
62 }
63
setUsage(unsigned int usage)64 void CredentialCriteria::setUsage(unsigned int usage)
65 {
66 m_keyUsage = usage;
67 }
68
getPeerName() const69 const char* CredentialCriteria::getPeerName() const
70 {
71 return m_peerName.empty() ? nullptr : m_peerName.c_str();
72 }
73
setPeerName(const char * peerName)74 void CredentialCriteria::setPeerName(const char* peerName)
75 {
76 m_peerName.erase();
77 if (peerName)
78 m_peerName = peerName;
79 }
80
getKeyAlgorithm() const81 const char* CredentialCriteria::getKeyAlgorithm() const
82 {
83 return m_keyAlgorithm.empty() ? nullptr : m_keyAlgorithm.c_str();
84 }
85
setKeyAlgorithm(const char * keyAlgorithm)86 void CredentialCriteria::setKeyAlgorithm(const char* keyAlgorithm)
87 {
88 m_keyAlgorithm.erase();
89 if (keyAlgorithm)
90 m_keyAlgorithm = keyAlgorithm;
91 }
92
getKeySize() const93 unsigned int CredentialCriteria::getKeySize() const
94 {
95 return m_keySize;
96 }
97
setKeySize(unsigned int keySize)98 void CredentialCriteria::setKeySize(unsigned int keySize)
99 {
100 m_keySize = keySize;
101 }
102
getMaxKeySize() const103 unsigned int CredentialCriteria::getMaxKeySize() const
104 {
105 return m_maxKeySize;
106 }
107
setMaxKeySize(unsigned int keySize)108 void CredentialCriteria::setMaxKeySize(unsigned int keySize)
109 {
110 m_maxKeySize = keySize;
111 }
112
setXMLAlgorithm(const XMLCh * algorithm)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
getKeyNames() const126 const set<string>& CredentialCriteria::getKeyNames() const
127 {
128 return m_keyNames;
129 }
130
getKeyNames()131 set<string>& CredentialCriteria::getKeyNames()
132 {
133 return m_keyNames;
134 }
135
getPublicKey() const136 XSECCryptoKey* CredentialCriteria::getPublicKey() const
137 {
138 return m_key;
139 }
140
setPublicKey(XSECCryptoKey * key)141 void CredentialCriteria::setPublicKey(XSECCryptoKey* key)
142 {
143 m_key = key;
144 }
145
getKeyInfo() const146 const KeyInfo* CredentialCriteria::getKeyInfo() const
147 {
148 return m_keyInfo;
149 }
150
setKeyInfo(const KeyInfo * keyInfo,int extraction)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
getNativeKeyInfo() const171 DSIGKeyInfoList* CredentialCriteria::getNativeKeyInfo() const
172 {
173 return m_nativeKeyInfo;
174 }
175
setNativeKeyInfo(DSIGKeyInfoList * keyInfo,int extraction)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
setSignature(const Signature & sig,int extraction)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
reset()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
matches(const Credential & credential) const218 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 }
300