Convert from NULL macro to nullptr.
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / CredentialCriteria.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * CredentialCriteria.cpp
19  *
20  * Class for specifying criteria by which a CredentialResolver should resolve credentials.
21  */
22
23 #include "internal.h"
24 #include "logging.h"
25 #include "XMLToolingConfig.h"
26 #include "security/X509Credential.h"
27 #include "security/CredentialCriteria.h"
28 #include "security/KeyInfoResolver.h"
29 #include "security/SecurityHelper.h"
30 #include "signature/Signature.h"
31
32 #include <openssl/dsa.h>
33 #include <openssl/rsa.h>
34 #include <xsec/dsig/DSIGKeyInfoList.hpp>
35 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
36 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
37
38 using xmlsignature::KeyInfo;
39 using xmlsignature::Signature;
40 using namespace xmltooling::logging;
41 using namespace xmltooling;
42 using namespace std;
43
44 CredentialCriteria::CredentialCriteria()
45     : m_keyUsage(Credential::UNSPECIFIED_CREDENTIAL), m_keySize(0), m_key(nullptr),
46         m_keyInfo(nullptr), m_nativeKeyInfo(nullptr), m_credential(nullptr)
47 {
48 }
49
50 CredentialCriteria::~CredentialCriteria()
51 {
52     delete m_credential;
53 }
54
55 unsigned int CredentialCriteria::getUsage() const
56 {
57     return m_keyUsage;
58 }
59
60 void CredentialCriteria::setUsage(unsigned int usage)
61 {
62     m_keyUsage = usage;
63 }
64
65 const char* CredentialCriteria::getPeerName() const
66 {
67     return m_peerName.c_str();
68 }
69
70 void CredentialCriteria::setPeerName(const char* peerName)
71 {
72     m_peerName.erase();
73     if (peerName)
74         m_peerName = peerName;
75 }
76
77 const char* CredentialCriteria::getKeyAlgorithm() const
78 {
79     return m_keyAlgorithm.c_str();
80 }
81
82 void CredentialCriteria::setKeyAlgorithm(const char* keyAlgorithm)
83 {
84     m_keyAlgorithm.erase();
85     if (keyAlgorithm)
86         m_keyAlgorithm = keyAlgorithm;
87 }
88
89 unsigned int CredentialCriteria::getKeySize() const
90 {
91     return m_keySize;
92 }
93
94 void CredentialCriteria::setKeySize(unsigned int keySize)
95 {
96     m_keySize = keySize;
97 }
98
99 void CredentialCriteria::setXMLAlgorithm(const XMLCh* algorithm)
100 {
101     if (algorithm) {
102         pair<const char*,unsigned int> mapped = XMLToolingConfig::getConfig().mapXMLAlgorithmToKeyAlgorithm(algorithm);
103         setKeyAlgorithm(mapped.first);
104         setKeySize(mapped.second);
105     }
106     else {
107         setKeyAlgorithm(nullptr);
108         setKeySize(0);
109     }
110 }
111
112 const set<string>& CredentialCriteria::getKeyNames() const
113 {
114     return m_keyNames;
115 }
116
117 set<string>& CredentialCriteria::getKeyNames()
118 {
119     return m_keyNames;
120 }
121
122 XSECCryptoKey* CredentialCriteria::getPublicKey() const
123 {
124     return m_key;
125 }
126
127 void CredentialCriteria::setPublicKey(XSECCryptoKey* key)
128 {
129     m_key = key;
130 }
131
132 const KeyInfo* CredentialCriteria::getKeyInfo() const
133 {
134     return m_keyInfo;
135 }
136
137 void CredentialCriteria::setKeyInfo(const KeyInfo* keyInfo, int extraction)
138 {
139     delete m_credential;
140     m_credential = nullptr;
141     m_keyInfo = keyInfo;
142     if (!keyInfo || !extraction)
143         return;
144
145     int types = (extraction & KEYINFO_EXTRACTION_KEY) ? Credential::RESOLVE_KEYS : 0;
146     types |= (extraction & KEYINFO_EXTRACTION_KEYNAMES) ? X509Credential::RESOLVE_CERTS : 0;
147     m_credential = XMLToolingConfig::getConfig().getKeyInfoResolver()->resolve(keyInfo,types);
148
149     // Ensure any key names have been sucked out for later if desired.
150     if (extraction & KEYINFO_EXTRACTION_KEYNAMES) {
151         X509Credential* xcred = dynamic_cast<X509Credential*>(m_credential);
152         if (xcred)
153             xcred->extract();
154     }
155 }
156
157 DSIGKeyInfoList* CredentialCriteria::getNativeKeyInfo() const
158 {
159     return m_nativeKeyInfo;
160 }
161
162 void CredentialCriteria::setNativeKeyInfo(DSIGKeyInfoList* keyInfo, int extraction)
163 {
164     delete m_credential;
165     m_credential = nullptr;
166     m_nativeKeyInfo = keyInfo;
167     if (!keyInfo || !extraction)
168         return;
169
170     int types = (extraction & KEYINFO_EXTRACTION_KEY) ? Credential::RESOLVE_KEYS : 0;
171     types |= (extraction & KEYINFO_EXTRACTION_KEYNAMES) ? X509Credential::RESOLVE_CERTS : 0;
172     m_credential = XMLToolingConfig::getConfig().getKeyInfoResolver()->resolve(keyInfo,types);
173
174     // Ensure any key names have been sucked out for later if desired.
175     if (extraction & KEYINFO_EXTRACTION_KEYNAMES) {
176         X509Credential* xcred = dynamic_cast<X509Credential*>(m_credential);
177         if (xcred)
178             xcred->extract();
179     }
180 }
181
182 void CredentialCriteria::setSignature(const Signature& sig, int extraction)
183 {
184     setXMLAlgorithm(sig.getSignatureAlgorithm());
185     KeyInfo* k = sig.getKeyInfo();
186     if (k)
187         return setKeyInfo(k, extraction);
188     DSIGSignature* dsig = sig.getXMLSignature();
189     if (dsig)
190         setNativeKeyInfo(dsig->getKeyInfoList(), extraction);
191 }
192
193 bool CredentialCriteria::matches(const Credential& credential) const
194 {
195     Category& log = Category::getInstance(XMLTOOLING_LOGCAT".CredentialCriteria");
196
197     // Usage check, if specified and we have one, compare masks.
198     if (getUsage() != Credential::UNSPECIFIED_CREDENTIAL) {
199         if (credential.getUsage() != Credential::UNSPECIFIED_CREDENTIAL)
200             if ((getUsage() & credential.getUsage()) == 0) {
201                 if (log.isDebugEnabled())
202                     log.debug("usage didn't match (%u != %u)", getUsage(), credential.getUsage());
203                 return false;
204             }
205     }
206
207     // Algorithm check, if specified and we have one.
208     const char* alg = getKeyAlgorithm();
209     if (alg && *alg) {
210         const char* alg2 = credential.getAlgorithm();
211         if (alg2 && *alg2) {
212             if (strcmp(alg,alg2)) {
213                 if (log.isDebugEnabled())
214                     log.debug("key algorithm didn't match ('%s' != '%s')", getKeyAlgorithm(), credential.getAlgorithm());
215                 return false;
216             }
217         }
218     }
219
220     // KeySize check, if specified and we have one.
221     if (credential.getKeySize()>0 && getKeySize()>0 && credential.getKeySize() != getKeySize()) {
222         if (log.isDebugEnabled())
223             log.debug("key size didn't match (%u != %u)", getKeySize(), credential.getKeySize());
224         return false;
225     }
226
227     // See if we can test key names.
228     set<string> critnames = getKeyNames();
229     if (m_credential)
230         critnames.insert(m_credential->getKeyNames().begin(), m_credential->getKeyNames().end());
231     const set<string>& crednames = credential.getKeyNames();
232     if (!critnames.empty() && !crednames.empty()) {
233         bool found = false;
234         for (set<string>::const_iterator n = critnames.begin(); n!=critnames.end(); ++n) {
235             if (crednames.count(*n)>0) {
236                 found = true;
237                 break;
238             }
239         }
240         if (!found) {
241             log.debug("credential name(s) didn't overlap");
242             return false;
243         }
244     }
245
246     // See if we have to match a specific key.
247     const XSECCryptoKey* key1 = getPublicKey();
248     if (!key1 && m_credential)
249         key1 = m_credential->getPublicKey();
250     if (!key1)
251         return true;    // no key to compare against, so we're done
252
253     const XSECCryptoKey* key2 = credential.getPublicKey();
254     if (!key2)
255         return true;   // no key here, so we can't test it
256
257     if (SecurityHelper::matches(*key1, *key2))
258         return true;
259     
260     log.debug("keys didn't match");
261     return false;
262 }