Major revamp of credential and trust handling code, PKIX engine still needs work.
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / BasicX509Credential.cpp
1 /*
2  *  Copyright 2001-2007 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  * BasicX509Credential.cpp
19  * 
20  * Wraps an X.509-based Credential by storing key/cert objects inside. 
21  */
22
23 #include "internal.h"
24 #include "security/BasicX509Credential.h"
25 #include "signature/KeyInfo.h"
26
27 #include <algorithm>
28 #include <openssl/x509v3.h>
29 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
30
31 using namespace xmlsignature;
32 using namespace xmltooling;
33 using namespace std;
34
35 BasicX509Credential::~BasicX509Credential()
36 {
37     delete m_key;
38     if (m_ownCerts)
39         for_each(m_xseccerts.begin(), m_xseccerts.end(), xmltooling::cleanup<XSECCryptoX509>());
40     delete m_crl;
41     delete m_keyInfo;
42     delete m_compactKeyInfo;
43 }
44
45 void BasicX509Credential::initKeyInfo()
46 {
47     delete m_keyInfo;
48     m_keyInfo = NULL;
49     delete m_compactKeyInfo;
50     m_compactKeyInfo = NULL;
51
52     vector<string> names;
53     if (getKeyNames(names)>0) {
54         m_compactKeyInfo = KeyInfoBuilder::buildKeyInfo();
55         VectorOf(KeyName) knames = m_compactKeyInfo->getKeyNames();
56         for (vector<string>::const_iterator n = names.begin(); n!=names.end(); ++n) {
57             xmltooling::auto_ptr_XMLCh wide(n->c_str());
58             KeyName* kname = KeyNameBuilder::buildKeyName();
59             kname->setName(wide.get());
60             knames.push_back(kname);
61         }
62     }
63     
64     if (!m_xseccerts.empty()) {
65         m_keyInfo = m_compactKeyInfo ? m_compactKeyInfo->cloneKeyInfo() : KeyInfoBuilder::buildKeyInfo();
66         X509Data* x509Data=X509DataBuilder::buildX509Data();
67         m_keyInfo->getX509Datas().push_back(x509Data);
68         for (vector<XSECCryptoX509*>::const_iterator x = m_xseccerts.begin(); x!=m_xseccerts.end(); ++x) {
69             safeBuffer& buf=(*x)->getDEREncodingSB();
70             X509Certificate* x509=X509CertificateBuilder::buildX509Certificate();
71             x509->setValue(buf.sbStrToXMLCh());
72             x509Data->getX509Certificates().push_back(x509);
73         }
74     }
75 }
76
77 vector<string>::size_type BasicX509Credential::getKeyNames(vector<string>& results) const
78 {
79     if (m_xseccerts.empty() || m_xseccerts.front()->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL)
80         return 0;
81     
82     X509* cert = static_cast<OpenSSLCryptoX509*>(m_xseccerts.front())->getOpenSSLX509();
83     if (!cert)
84         return 0;
85         
86     X509_NAME* subject=X509_get_subject_name(cert);
87     if (subject) {
88         char buf[256];
89         memset(buf,0,sizeof(buf));
90         if (X509_NAME_get_text_by_NID(subject,NID_commonName,buf,255)>0)
91             results.push_back(buf);
92
93         STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
94         if (altnames) {
95             string alt;
96             int numalts = sk_GENERAL_NAME_num(altnames);
97             for (int an=0; an<numalts; an++) {
98                 const GENERAL_NAME* check = sk_GENERAL_NAME_value(altnames, an);
99                 if (check->type==GEN_DNS || check->type==GEN_URI) {
100                     const char* altptr = (char*)ASN1_STRING_data(check->d.ia5);
101                     const int altlen = ASN1_STRING_length(check->d.ia5);
102                     if (altlen>0) {
103                         alt.erase();
104                         alt.append(altptr,altlen);
105                         results.push_back(alt);
106                     }
107                 }
108             }
109         }
110         GENERAL_NAMES_free(altnames);
111     }
112
113     return results.size();
114 }