PKIFCryptoPPUtils.cpp

Go to the documentation of this file.
00001 
00010 #include "PKIFCryptoPPUtils.h"
00011 #include "PKIFCryptoPPKeyMaterial.h"
00012 #include "PKIFCryptoPPCredential.h"
00013 
00014 #include "FileUtils.h"
00015 #include "PKIFBase64.h"
00016 #include "Buffer.h"
00017 #include "OID.h"
00018 #include "PKIFMemoryUtils.h"
00019 
00020 #include "PKIFCredential.h"
00021 #include "PKIFKeyMaterial.h"
00022 #include "SubjectPublicKeyInfo.h"
00023 #include "Certificate.h"
00024 
00025 #include "ASN1Helper.h"
00026 #include "PKIX1Explicit88.h"
00027 #include "ECC-CMS.h"
00028 
00029 #include "PKIFAlgorithm.h"
00030 
00031 #if defined(WIN32) || defined(_WIN32)
00032     #include <Winsock2.h>
00033 #endif
00034 
00035 #if !defined(_WIN32)
00036 #include <netinet/in.h>
00037 #endif
00038 
00039 #include "boost/filesystem/path.hpp"
00040 #include "boost/filesystem/operations.hpp"
00041 #include "boost/filesystem/fstream.hpp"
00042 #include "boost/scoped_ptr.hpp"
00043 #include <iostream>
00044 #include <sstream>
00045 
00046 #include "boost/numeric/conversion/cast.hpp"
00047 #include "boost/numeric/conversion/bounds.hpp"
00048 #include "boost/limits.hpp"
00049 
00050 #include "cryptlib.h"
00051 #include "queue.h"
00052 #include "asn.h"
00053 #include "sha.h"
00054 
00055 #include <iostream>
00056 #include <strstream>
00057 
00058 
00059 using boost::numeric_cast;
00060 using boost::bad_numeric_cast;
00061 
00062 using namespace std;
00063 namespace fs = boost::filesystem;
00064 
00065 using namespace CryptoPP;
00066 
00067 using namespace boost;
00068 
00076 CPKIFBufferPtr GetTBSCertSequence(
00078       const CPKIFCertificate & cert)
00079 {
00080     CPKIFBufferPtr wholeCert = cert.Encoded();
00081     ByteQueue certReader, tbsCertWriter;
00082     certReader.Put(wholeCert->GetBuffer(),wholeCert->GetLength());
00083     BERSequenceDecoder x509Cert(certReader);
00084     BERSequenceDecoder tbsCert(x509Cert);
00085     DERSequenceEncoder tbsCertEnc(tbsCertWriter);
00086     tbsCert.CopyTo(tbsCertEnc);
00087     tbsCertEnc.MessageEnd();
00088     unsigned char * tbsCertBuf = 0;
00089 
00090     unsigned long size = 0;
00091     try 
00092     {
00093         size = numeric_cast<unsigned long>(tbsCertWriter.MaxRetrievable());
00094     }
00095     catch(bad_numeric_cast &) 
00096     {
00097         throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "Cert size is an impossibly long number.");
00098     }
00099     unsigned long tbsCertSize = size;
00100     tbsCertBuf = new unsigned char[tbsCertSize];
00101     tbsCertWriter.Get(tbsCertBuf,tbsCertSize);
00102     CPKIFBufferPtr tbsOut(new CPKIFBuffer(true,tbsCertBuf,tbsCertSize));
00103     return tbsOut;
00104 }
00112 CPKIFCredentialPtr _MakeCredentialFromP8File(
00114     const std::string & file)
00115 {
00116     // For the time being, this is suboptimal; crypto++ doesn't support any
00117     // password-protected store natively, so all it can use are clear PKCS#8
00118     // files
00119     CPKIFCredentialPtr rv((CPKIFCredential *)0);
00120     CPKIFBufferPtr filebuf = ReadFileIntoBuffer(file);
00121     unsigned char * derdata = 0;
00122     unsigned long derlen = 0;
00123     bool dataWasPEM = false;
00124     // sniff for PEM
00125     if(filebuf->GetBuffer()[0] == '-') {
00126         // if the first byte is '-' it's not DER and is most likely PEM
00127         char * bufstr = new char[filebuf->GetLength()+1];
00128         memcpy(bufstr,filebuf->GetBuffer(),filebuf->GetLength());
00129         bufstr[filebuf->GetLength()] = 0;
00130         if(!PEMDecode_l(bufstr,filebuf->GetLength(),&derdata,&derlen)) {
00131             delete[] bufstr;
00132             // XXX would we rather throw?
00133             return rv;
00134         }
00135         dataWasPEM = true;
00136         delete[] bufstr;
00137     } else {
00138         derdata = const_cast<unsigned char *>(filebuf->GetBuffer());
00139         derlen = filebuf->GetLength();
00140     }
00141 
00142     // just do enough processing on the key material to determine the algorithm.
00143     // further processing occurs during the sign operation.
00144     ByteQueue keyReader;
00145     keyReader.Put(derdata,derlen);
00146     BERSequenceDecoder privateKeyInfo(keyReader);
00147     word32 version;
00148     BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0);  // check version
00149     OID pkOID;
00150     BERSequenceDecoder algorithm(privateKeyInfo);
00151     pkOID.BERDecode(algorithm);
00152 
00153     int size = 0;
00154     try 
00155     {
00156         size = numeric_cast<int>(pkOID.m_values.size());
00157     }
00158     catch(bad_numeric_cast &) 
00159     {
00160         throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "Size is an impossibly long number.");
00161     }
00162 
00163     int ncomps = size;
00164     ostringstream os;
00165     for(int i = 0; i < ncomps; ++i)
00166     {
00167         os << pkOID.m_values[i];
00168         if(i != ncomps - 1) os << ".";
00169     }
00170     string oidStr = os.str();
00171     CPKIFOIDPtr keyOID(new CPKIFOID(oidStr));
00172     CPKIFAlgorithm * keyAlg = CPKIFAlgorithm::GetAlg(keyOID);
00173     // if no algorithm could be had, the key is unsupported in PKIF
00174     if(!keyAlg) {
00175         if(dataWasPEM) {
00176             PKIFZero(derdata,derlen);
00177             delete[] derdata;
00178         }
00179         return rv;
00180     }
00181     // once we know we understand the key and it's formatted properly,
00182     // dump it into a credential
00183     CPKIFCryptoPPCredentialPtr credOut(new CPKIFCryptoPPCredential());
00184     CPKIFBufferPtr keyBuf(new CPKIFBuffer(derdata,derlen));
00185     credOut->SetPrivateKey(keyBuf);
00186     credOut->SetAlgorithm(keyAlg);
00187     rv = dynamic_pointer_cast<CPKIFCredential,CPKIFCryptoPPCredential>(credOut);
00188     if(dataWasPEM) {
00189         PKIFZero(derdata,derlen);
00190         delete[] derdata;
00191     }
00192     return rv;
00193 }
00194 
00206 CPKIFCredentialPtr MakeCredentialFromP8File(
00208     const std::string & file)
00209 {
00210     return _MakeCredentialFromP8File(file);
00211 }
00223 CPKIFCredentialPtr MakeCredentialFromP8File(const std::string & file, const std::string & certFile )
00224 {
00225     CPKIFCredentialPtr cred = _MakeCredentialFromP8File(file);
00226     if(cred != (CPKIFCredential*)NULL)
00227     {
00228         CPKIFBufferPtr filebuf = ReadFileIntoBuffer(certFile);
00229         unsigned char * derdata = 0;
00230         unsigned long derlen = 0;
00231         bool dataWasPEM = false;
00232         // sniff for PEM
00233         if(filebuf->GetBuffer()[0] == '-') {
00234             // if the first byte is '-' it's not DER and is most likely PEM
00235             char * bufstr = new char[filebuf->GetLength()+1];
00236             memcpy(bufstr,filebuf->GetBuffer(),filebuf->GetLength());
00237             bufstr[filebuf->GetLength()] = 0;
00238             if(!PEMDecode_l(bufstr,filebuf->GetLength(),&derdata,&derlen)) {
00239                 delete[] bufstr;
00240                 // XXX would we rather throw?
00241                 return cred;
00242             }
00243             dataWasPEM = true;
00244             delete[] bufstr;
00245         } else {
00246             derdata = const_cast<unsigned char *>(filebuf->GetBuffer());
00247             derlen = filebuf->GetLength();
00248         }
00249 
00250         CPKIFCertificatePtr cert(new CPKIFCertificate);
00251         cert->Decode(derdata, derlen);
00252 
00253         CPKIFCryptoPPCredentialPtr cppCred = dynamic_pointer_cast<CPKIFCryptoPPCredential, CPKIFCredential>(cred);
00254         cppCred->SetCertificate(cert);
00255     }
00256     return cred;
00257 }
00258 
00267 CPKIFBufferPtr GetEncodedSPKIFromKM(const CPKIFKeyMaterial & km)
00268 {
00269     CPKIFCryptoPPKeyMaterialPtr cppKM(new CPKIFCryptoPPKeyMaterial(km));
00270     CPKIFBufferPtr rv = cppKM->GetRawSPKI();
00271     return rv;
00272 }
00273 
00283 CPKIFBufferPtr DeriveKeyFromSecret(
00285                                    const CPKIFBufferPtr & secret,
00287                                    const CPKIFBufferPtr & sharedInfo,
00290                                    unsigned int keyLength)
00291 {
00292     CPKIFBufferPtr rv;
00293 
00294     CACASNWRAPPER_CREATE(ECC_CMS_SharedInfo,ecsPDU);
00295 
00296     unsigned long derivedKeyLen = keyLength;
00297     
00298     // if the caller did not specify a key length, attempt to pull it out of the sharedInfo structure
00299     if(0 == derivedKeyLen) {
00300         ECC_CMS_SharedInfo * ecsi = ecsPDU.Decode(sharedInfo->GetBuffer(),sharedInfo->GetLength());
00301         if(!ecsi) throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "sharedInfo is invalid.");
00302         u_long nwKeySize32;
00303         if(ecsi->suppPubInfo.numocts > sizeof(u_long)) throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "sharedInfo is invalid.");
00304         memcpy(&nwKeySize32,ecsi->suppPubInfo.data,ecsi->suppPubInfo.numocts);
00305         u_long keySize32 = ntohl(nwKeySize32);
00306         derivedKeyLen = keySize32;
00307     }
00308 
00309     CryptoPP::HashTransformation * sha = 0;
00310 
00311     // select a hash according to Russ Housley's Suite B S/MIME draft, with allowance
00312     // for the fact that we support more key sizes. That only allows for AES128/256 keys.
00313     // since 192 is also supported here, we'll treat it like 256 for key generation purposes
00314     if(derivedKeyLen <= 16) {
00315         sha = new CryptoPP::SHA256();
00316     } else {
00317         sha = new CryptoPP::SHA384();
00318     }
00319     boost::scoped_ptr<CryptoPP::HashTransformation> pSha(sha);
00320 
00321     if(!pSha) throw std::runtime_error(string("Internal error: unable to instantiate hash object for key derivation"));
00322     
00323     // counter is constant for this
00324     unsigned char counter[4] = {0x00,0x00,0x00,0x01};
00325 
00326     pSha->Update(secret->GetBuffer(),secret->GetLength());
00327     pSha->Update(counter,4);
00328     pSha->Update(sharedInfo->GetBuffer(),sharedInfo->GetLength());
00329     unsigned int digestLen = sha->DigestSize();
00330     unsigned char * temp = new unsigned char[digestLen];
00331     try {
00332         pSha->Final(temp);
00333     }catch(std::exception & e){
00334         delete[] temp;
00335         throw e;
00336     }
00337     rv = CPKIFBufferPtr(new CPKIFBuffer(true,temp,digestLen));
00338     return rv;
00339 }

Generated on Mon Nov 15 11:15:54 2010 for PublicKeyInfrastructureFramework(PKIF) by  doxygen 1.5.6