/* * Copyright 2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * XSEC * * NSSCryptoX509:= NSS based class for handling X509 (V3) certificates * * Author(s): Milan Tomic * */ #include #include #include #include #include #include #include #include #if defined (HAVE_NSS) #include extern "C" { extern CERTCertificate * __CERT_DecodeDERCertificate (SECItem *derSignedCert, PRBool copyDER, char *nickname); } #include XSEC_USING_XERCES(ArrayJanitor); // -------------------------------------------------------------------------------- // Constructor // -------------------------------------------------------------------------------- NSSCryptoX509::NSSCryptoX509() : m_DERX509(""), mp_cert(NULL) { } // -------------------------------------------------------------------------------- // Constructor // -------------------------------------------------------------------------------- NSSCryptoX509::NSSCryptoX509(CERTCertificate * pCert) { // Build this from an existing CERTCertificate structure mp_cert = pCert; unsigned char * encCert; unsigned long len = mp_cert->derCert.len * 2; XSECnew(encCert, unsigned char [len]); ArrayJanitor j_encCert(encCert); // Base64 Encode XSCryptCryptoBase64 b64; b64.encodeInit(); unsigned long encCertLen = b64.encode(mp_cert->derCert.data, mp_cert->derCert.len, encCert, len); encCertLen += b64.encodeFinish(&encCert[encCertLen], len - encCertLen); // Check the result if (encCert == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSSX509:NSSX509 - Error encoding certificate"); } m_DERX509.sbMemcpyIn(encCert, encCertLen); m_DERX509[encCertLen] = '\0'; } // -------------------------------------------------------------------------------- // Destructor // -------------------------------------------------------------------------------- NSSCryptoX509::~NSSCryptoX509() { if (mp_cert != 0) CERT_DestroyCertificate(mp_cert); } // -------------------------------------------------------------------------------- // Load X509 // -------------------------------------------------------------------------------- void NSSCryptoX509::loadX509Base64Bin(const char * buf, unsigned int len) { unsigned char * rawCert; XSECnew(rawCert, unsigned char [len]); ArrayJanitor j_rawCert(rawCert); // Base64 Decode XSCryptCryptoBase64 b64; b64.decodeInit(); unsigned int rawCertLen = b64.decode((unsigned char *) buf, len, rawCert, len); rawCertLen += b64.decodeFinish(&rawCert[rawCertLen], len - rawCertLen); // Now load certificate SECItem i; i.type = siBuffer; i.data = rawCert; i.len = rawCertLen; SECItem *certs[1]; certs[0] = &i; // For returning CERTCertificate **certArray = NULL; /* mp_cert = __CERT_DecodeDERCertificate(&i, PR_TRUE, NULL); */ CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport, 1, certs, &certArray, PR_FALSE, PR_FALSE, NULL); // 1. If you got an compiler error here add into "nss/cert.h" delacarion for // CERT_DecodeDERCertificate() (the same parameters as for __CERT_DecodeDERCertificate()) // 2. Since __CERT_DecodeDERCertificate is a private function we might consider using // __CERT_NewTempCertificate() or CERT_ImportCerts() instead. // Now map to our cert if (certArray == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSSX509:loadX509Base64Bin - Error decoding certificate"); } mp_cert = certArray[0]; if (mp_cert == 0) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSSX509:loadX509Base64Bin - Error decoding certificate"); } m_DERX509.sbMemcpyIn(buf, len); m_DERX509[len] = '\0'; } // -------------------------------------------------------------------------------- // Get NSS provider name // -------------------------------------------------------------------------------- const XMLCh * NSSCryptoX509::getProviderName() { return DSIGConstants::s_unicodeStrPROVNSS; } // -------------------------------------------------------------------------------- // Get publickey type: RSA or DSA // -------------------------------------------------------------------------------- XSECCryptoKey::KeyType NSSCryptoX509::getPublicKeyType() { if (mp_cert == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSS:X509 - getPublicKeyType called before X509 loaded"); } XSECCryptoKey::KeyType kt = XSECCryptoKey::KEY_NONE; SECKEYPublicKey * pubkey = CERT_ExtractPublicKey(mp_cert); if (pubkey == 0) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSS:X509 - Error extracting public key from X509 certificate"); } if (pubkey->keyType == dsaKey) kt = XSECCryptoKey::KEY_DSA_PUBLIC; if (pubkey->keyType == rsaKey) kt = XSECCryptoKey::KEY_RSA_PUBLIC; SECKEY_DestroyPublicKey(pubkey); return kt; } // -------------------------------------------------------------------------------- // Replicate public key // -------------------------------------------------------------------------------- XSECCryptoKey * NSSCryptoX509::clonePublicKey() { if (mp_cert == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "NSS:X509 - clonePublicKey called before X509 loaded"); } // Import the key into the provider to get a pointer to the key if (getPublicKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC) { SECKEYPublicKey * pubkey = CERT_ExtractPublicKey(mp_cert); // Now that we have a handle for the DSA key, create a DSA Key object to // wrap it in NSSCryptoKeyDSA * ret; XSECnew(ret, NSSCryptoKeyDSA(pubkey)); return ret; } if (getPublicKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC) { SECKEYPublicKey * pubkey = CERT_ExtractPublicKey(mp_cert); // Now that we have a handle for the DSA key, create a DSA Key object to // wrap it in NSSCryptoKeyRSA * ret; XSECnew(ret, NSSCryptoKeyRSA(pubkey)); return ret; } return NULL; // Unknown key type, but not necessarily an error } #endif /* HAVE_NSS */