Mixe for Privacy and Anonymity in the Internet
CACertificate.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team
00003 All rights reserved.
00004 Redistribution and use in source and binary forms, with or without modification,
00005 are permitted provided that the following conditions are met:
00006 
00007   - Redistributions of source code must retain the above copyright notice,
00008     this list of conditions and the following disclaimer.
00009 
00010   - Redistributions in binary form must reproduce the above copyright notice,
00011     this list of conditions and the following disclaimer in the documentation and/or
00012     other materials provided with the distribution.
00013 
00014   - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
00015     may be used to endorse or promote products derived from this software without specific
00016     prior written permission.
00017 
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
00020 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00021 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
00022 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00025 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00027 */
00028 
00029 #include "StdAfx.h"
00030 #ifndef ONLY_LOCAL_PROXY
00031 #include "CACertificate.hpp"
00032 #include "CABase64.hpp"
00033 #include "CAUtil.hpp"
00034 #include "CAMsg.hpp"
00035 
00036 UINT8 * CACertificate::m_spXmlElementName =0;
00037 
00038 CACertificate::CACertificate()
00039   {
00040     m_pCert = NULL;
00041     m_pSKI = NULL;
00042     m_pAKI = NULL;
00043   }
00044 
00045 CACertificate::CACertificate(X509* x)
00046   {
00047     m_pCert = x;
00048     m_pSKI = NULL;
00049     m_pAKI = NULL;
00050     if(m_pCert != NULL)
00051       {
00052         m_pSKI = (ASN1_OCTET_STRING*) X509_get_ext_d2i(m_pCert, NID_subject_key_identifier, NULL, NULL);
00053         m_pAKI = (AUTHORITY_KEYID*) X509_get_ext_d2i (m_pCert, NID_authority_key_identifier, NULL, NULL);
00054       }
00055   }
00056 
00057 CACertificate* CACertificate::decode(const DOMNode* n,UINT32 type,const char* passwd)
00058   {
00059     const DOMNode* node=n;
00060     switch(type)
00061       {
00062         case CERT_PKCS12:
00063           while(node!=NULL)
00064             {
00065               if(equals(node->getNodeName(),"X509PKCS12"))
00066                 {
00067                   UINT32 strLen=4096;
00068                   UINT8* tmpStr=new UINT8[strLen];
00069                   CACertificate* cert=NULL;
00070                   if(getDOMElementValue(node,tmpStr,&strLen)!=E_SUCCESS)
00071                     {
00072                       delete[] tmpStr;
00073                       tmpStr = NULL;
00074                       return NULL;
00075                     }
00076                   UINT32 decLen=4096;
00077                   UINT8* decBuff=new UINT8[decLen];
00078                   SINT32 ret=CABase64::decode((UINT8*)tmpStr,strLen,decBuff,&decLen);
00079                   delete[] tmpStr;
00080                   tmpStr = NULL;
00081                   if(ret==E_SUCCESS)
00082                     {
00083                       cert=decode(decBuff,decLen,CERT_PKCS12,passwd);
00084                     }
00085                   delete[] decBuff;
00086                   decBuff = NULL;
00087                   return cert;
00088                 }
00089               node=node->getNextSibling();
00090             }
00091         break;
00092         case  CERT_X509CERTIFICATE:
00093           while(node!=NULL)
00094             {
00095               if(equals(node->getNodeName(),"X509Certificate"))
00096                 {
00097                   UINT32 strLen=4096;
00098                   UINT8* tmpStr=new UINT8[strLen];
00099                   CACertificate* cert=NULL;
00100                   if(getDOMElementValue(node,tmpStr,&strLen)!=E_SUCCESS)
00101                     {
00102                       delete[] tmpStr;
00103                       tmpStr = NULL;
00104                       return NULL;
00105                     }
00106                   UINT32 decLen=4096;
00107                   UINT8* decBuff=new UINT8[decLen];
00108                   SINT32 ret=CABase64::decode((UINT8*)tmpStr,strLen,decBuff,&decLen);
00109                   delete[] tmpStr;
00110                   tmpStr = NULL;
00111                   if(ret==E_SUCCESS)
00112                     {
00113                       cert=decode(decBuff,decLen,CERT_DER);
00114                     }
00115                   delete[] decBuff;
00116                   decBuff = NULL;
00117                   return cert;
00118                 }
00119               node=node->getNextSibling();
00120             }
00121 
00122       }
00123     return NULL;
00124   }
00125 
00126 CACertificate* CACertificate::decode(const UINT8* const buff,UINT32 bufflen,UINT32 type,const char* const passwd)
00127   {
00128     if(buff==NULL)
00129       return NULL;
00130     X509* tmpCert=NULL;
00131     EVP_PKEY* tmpKey=NULL;
00132     SINT32 ret=-1;
00133     const UINT8* tmp=buff;
00134     switch(type)
00135       {
00136         case CERT_DER:
00137           tmp=buff;
00138           #if OPENSSL_VERSION_NUMBER  > 0x009070CfL
00139             tmpCert=d2i_X509(NULL,&tmp,bufflen);
00140           #else
00141             tmpCert=d2i_X509(NULL,(UINT8**)&tmp,bufflen);
00142           #endif
00143         break;
00144         case CERT_PKCS12:
00145           PKCS12* tmpPKCS12;
00146           #if OPENSSL_VERSION_NUMBER  > 0x009070CfL
00147             tmpPKCS12=d2i_PKCS12(NULL,&tmp,bufflen);
00148           #else
00149             tmpPKCS12=d2i_PKCS12(NULL,(UINT8**)&tmp,bufflen);
00150           #endif
00151           /*Note: Basically we are not interested in the private keys here - but still we need cannot supply
00152            *NULL for that parameter, as OpenSSL 1.0.0. would not work in that case*/
00153           ret=PKCS12_parse(tmpPKCS12,passwd,&tmpKey,&tmpCert,NULL);
00154           PKCS12_free(tmpPKCS12);
00155           EVP_PKEY_free(tmpKey);
00156           if(ret!=1)
00157             {
00158               return NULL;
00159             }
00160         break;
00161         case CERT_XML_X509CERTIFICATE:
00162           XERCES_CPP_NAMESPACE::DOMDocument* doc=parseDOMDocument(buff,bufflen);
00163           if(doc == NULL)
00164           {
00165             return NULL;
00166           }
00167           DOMElement* root=doc->getDocumentElement();
00168           if(root==NULL||!equals(root->getNodeName(),"X509Certificate"))
00169           {
00170             return NULL;
00171           }
00172           UINT8* tmpBuff=new UINT8[bufflen];
00173           UINT32 tmpBuffSize=bufflen;
00174           if(getDOMElementValue(root,tmpBuff,&tmpBuffSize)==E_SUCCESS)
00175             {
00176               ret=CABase64::decode(tmpBuff,tmpBuffSize,tmpBuff,&tmpBuffSize);
00177             }
00178           tmp=tmpBuff;
00179           if(ret==E_SUCCESS)
00180             {
00181               #if OPENSSL_VERSION_NUMBER  > 0x009070CfL
00182                 tmpCert=d2i_X509(NULL,&tmp,tmpBuffSize);
00183               #else
00184                 tmpCert=d2i_X509(NULL,(UINT8**)&tmp,tmpBuffSize);
00185               #endif
00186             }
00187           delete[] tmpBuff;
00188           tmpBuff = NULL;
00189           break;
00190       }
00191     if(tmpCert == NULL)
00192     {
00193       return NULL;
00194     }
00195     return new CACertificate(tmpCert);
00196   }
00197 
00198 SINT32 CACertificate::encode(UINT8* buff,UINT32* bufflen,UINT32 type) const
00199   {
00200     if(m_pCert==NULL||buff==NULL||bufflen==NULL)
00201       return E_UNKNOWN;
00202     int i=0;
00203     UINT8* tmp=buff;
00204     switch(type)
00205       {
00206         case CERT_DER:
00207           i=i2d_X509(m_pCert,&tmp);
00208           if(i==0)
00209             return E_UNKNOWN;
00210           *bufflen=i;
00211         break;
00212         case CERT_XML_X509CERTIFICATE:
00213         #define X509_CERTIFICATE_TAGNAME_LEN 17
00214           memcpy(buff,"<X509Certificate>",X509_CERTIFICATE_TAGNAME_LEN); //we start with '<X509Certificate>'
00215           tmp+=X509_CERTIFICATE_TAGNAME_LEN;
00216           i=i2d_X509(m_pCert,&tmp); //now we need DER
00217           if(i==0)
00218             return E_UNKNOWN;
00219           CABase64::encode( buff+X509_CERTIFICATE_TAGNAME_LEN,i,
00220                             buff+X509_CERTIFICATE_TAGNAME_LEN,bufflen); //now we have it converted to Base64
00221           memcpy( buff+X509_CERTIFICATE_TAGNAME_LEN+*bufflen,
00222                   "</X509Certificate>",X509_CERTIFICATE_TAGNAME_LEN+1); //we end it with '</X509Certificate>'
00223           *bufflen+=2*X509_CERTIFICATE_TAGNAME_LEN+1;
00224         break;
00225         default:
00226           return E_UNKNOWN;
00227       }
00228     return E_SUCCESS;
00229   }
00230 
00231 SINT32 CACertificate::encode(DOMElement* & elemRoot,XERCES_CPP_NAMESPACE::DOMDocument* doc) const
00232   {
00233     elemRoot=createDOMElement(doc,"X509Certificate");
00234     UINT8 buff[2048]; //TODO: Very bad --> looks like easy buffer overflow... [donn't care at the moment...]
00235     UINT8* tmp=buff;
00236     int i=i2d_X509(m_pCert,&tmp); //now we need DER
00237     UINT32 bufflen=2048;
00238     CABase64::encode(buff,i,buff,&bufflen); //now we have it converted to Base64
00239     buff[bufflen]=0;
00240     setDOMElementValue(elemRoot,buff);
00241     return E_SUCCESS;
00242   }
00243 
00252 SINT32 CACertificate::getSubjectKeyIdentifier(UINT8* r_ski, UINT32 *r_skiLen)
00253 {
00254     if (m_pSKI == NULL)
00255     {
00256 #ifdef DEBUG
00257         CAMsg::printMsg( LOG_ERR, "Unable to get SKI from Certificate, trying to recover\n");
00258 #endif
00259         setSubjectKeyIdentifier();
00260         if(m_pSKI == NULL)
00261         {
00262             CAMsg::printMsg( LOG_ERR, "Unable to retrieve 1SKI from Certificate\n");
00263             return E_UNKNOWN;
00264         }
00265 #ifdef DEBUG
00266         else
00267         {
00268             CAMsg::printMsg( LOG_ERR, "Recovery SUCCESSFUL!\n");
00269         }
00270 #endif
00271     }
00272     // Get the ASCII string format of the subject key identifier
00273     UINT8* cSki = (UINT8*)i2s_ASN1_OCTET_STRING( NULL, m_pSKI );
00274     if ( cSki==NULL )
00275     {
00276         CAMsg::printMsg( LOG_ERR, "Unable to convert SKI\n");
00277         return E_UNKNOWN;
00278     }
00279 #ifdef DEBUG
00280     CAMsg::printMsg( LOG_ERR, "getSubjectKeyIdentifier: SKI is %s\n", cSki);
00281 #endif
00282     removeColons(cSki, strlen((const char*)cSki), r_ski, r_skiLen);
00283   OPENSSL_free(cSki);
00284     return E_SUCCESS;
00285 }
00286 
00287 SINT32 CACertificate::getAuthorityKeyIdentifier(UINT8* r_aki, UINT32* r_akiLen) const
00288 {
00289   if(m_pAKI == NULL)
00290   {
00291     return E_UNKNOWN;
00292   }
00293 
00294   ASN1_OCTET_STRING* pKeyID = NULL;
00295   pKeyID = m_pAKI->keyid;
00296   if(pKeyID == NULL)
00297   {
00298     return E_UNKNOWN;
00299   }
00300 
00301   // Get the ASCII string format of the authority key identifier
00302   UINT8* cKeyID = (UINT8*)i2s_ASN1_OCTET_STRING(NULL, pKeyID);
00303   if (cKeyID == NULL)
00304   {
00305     return E_UNKNOWN;
00306   }
00307   removeColons(cKeyID, strlen((const char*)cKeyID), r_aki, r_akiLen);
00308   OPENSSL_free(cKeyID);
00309   return E_SUCCESS;
00310 }
00311 
00324 SINT32 CACertificate::removeColons(const UINT8* a_cSkid, UINT32 a_cSkidLen, UINT8 *&r_ski, UINT32 *r_skiLen)
00325 {
00326     UINT32 i = 0, j = 0;
00327     UINT32 tmp = (2*a_cSkidLen)/3 + 2;
00328     if(*r_skiLen < tmp)
00329     {
00330         CAMsg::printMsg( LOG_ERR, "CACertificate::removeColons: Unable to copy SKI to target array, size must at least be %i but is only %i!\n", tmp, *r_skiLen);
00331         return E_UNKNOWN;
00332     }
00333     for(i = 0; i < a_cSkidLen; i++)
00334     {
00335         if(i % 3 == 2) {
00336             j++;
00337             continue;
00338         }
00339         r_ski[i-j] = a_cSkid[i];
00340     }
00341     r_ski[i-j] = 0;
00342     *r_skiLen = i-j;
00343     return E_SUCCESS;
00344 }
00345 
00352 SINT32 CACertificate::setSubjectKeyIdentifier()
00353 {
00354     UINT32 len = 0;
00355     UINT8 sha_hash[SHA_DIGEST_LENGTH];
00356     X509_pubkey_digest(m_pCert, EVP_sha1(), sha_hash, &len);
00357     return setSubjectKeyIdentifier( sha_hash, len );
00358 }
00359 
00368 SINT32 CACertificate::setSubjectKeyIdentifier( UINT8* a_value, UINT32 a_valueLen )
00369 {
00370     SINT32 ret = E_UNKNOWN;
00371     ASN1_OCTET_STRING* skid = NULL;
00372 
00373     skid = ASN1_OCTET_STRING_new();
00374     if(NULL == skid)   goto end;
00375 
00376     ASN1_OCTET_STRING_set(skid, a_value, a_valueLen);
00377     if( X509_add1_ext_i2d(m_pCert, NID_subject_key_identifier, skid, false, X509V3_ADD_REPLACE) == 1)
00378     {
00379       m_pSKI = skid;
00380       ret = E_SUCCESS;
00381     }
00382 
00383 end:
00384     //ASN1_OCTET_STRING_free(skid);
00385     return ret;
00386 }
00387 
00388 SINT32 CACertificate::getRawSubjectKeyIdentifier(UINT8* r_ski, UINT32* r_skiLen)
00389 {
00390   if (m_pSKI == NULL)
00391   {
00392     setSubjectKeyIdentifier();
00393     if(m_pSKI == NULL)
00394     {
00395       CAMsg::printMsg( LOG_ERR, "Unable to retrieve raw SKI from Certificate\n");
00396       return E_UNKNOWN;
00397         }
00398 
00399   }
00400   if(*r_skiLen < (UINT32) m_pSKI->length)
00401   {
00402     CAMsg::printMsg( LOG_ERR, "Unable to copy SKI to target array, size must at least be %i but is only %i!\n", m_pSKI->length, r_skiLen );
00403     return E_UNKNOWN;
00404   }
00405   *r_skiLen = m_pSKI->length;
00406   for(SINT32 i=0; i<m_pSKI->length; i++)
00407   {
00408     r_ski[i] = m_pSKI->data[i];
00409   }
00410   return E_SUCCESS;
00411 }
00412 
00413 SINT32 CACertificate::verify(const CACertificate* a_cert) const
00414 {
00415   if(a_cert == NULL || a_cert->m_pCert == NULL || m_pCert == NULL)
00416   {
00417     return E_UNKNOWN;
00418   }
00419   //check validity
00420   if(!isValid())
00421   {
00422     CAMsg::printMsg(LOG_ERR, "Verification Error: Certificate is not valid!\n");
00423     return E_UNKNOWN;
00424   }
00425   //namechaining...
00426   if(X509_NAME_cmp(X509_get_issuer_name(m_pCert), X509_get_subject_name(a_cert->m_pCert)) != 0)
00427   {
00428     CAMsg::printMsg(LOG_ERR, "Verification Error: Names do not match!\n");
00429     return E_UNKNOWN;
00430   }
00431   //keychaining... (only if available)
00432   if(m_pAKI != NULL && a_cert->m_pSKI != NULL)
00433   {
00434     if(ASN1_OCTET_STRING_cmp(m_pAKI->keyid, a_cert->m_pSKI) != 0)
00435     {
00436       CAMsg::printMsg(LOG_ERR, "Verification Error: Key Identifiers do not match!\n");
00437       return E_UNKNOWN;
00438     }
00439   }
00440   //get public key
00441   EVP_PKEY* pubKey = X509_get_pubkey(a_cert->m_pCert);
00442   if(pubKey == NULL)
00443   {
00444     CAMsg::printMsg(LOG_ERR, "Verification Error: Public Key is NULL!\n");
00445     return E_UNKNOWN;
00446   }
00447   //check if public key and signature algorithm match -> does not work because of openssl bug!
00448   //SINT32 sigType = X509_get_signature_type(m_pCert);
00449   /*SINT32 sigType = OBJ_obj2nid((m_pCert)->sig_alg->algorithm);
00450   SINT32 keyType = EVP_PKEY_type(pubKey->type);
00451   CAMsg::printMsg(LOG_DEBUG, "sigType is %d and keyType is %d\n", sigType, keyType);
00452   if((sigType != (NID_dsaWithSHA1 || NID_sha1WithRSAEncryption ||NID_ecdsa_with_SHA1))
00453       && keyType != EVP_PKEY_DSA) ||
00454      (sigType == NID_sha1WithRSAEncryption && keyType != EVP_PKEY_RSA) ||
00455      (sigType == NID_ecdsa_with_SHA1 && keyType != EVP_PKEY_EC))
00456   {
00457     CAMsg::printMsg(LOG_ERR, "Verification Error: Signature Algorithm does not match!\n");
00458     //return E_UNKNOWN;
00459   }*/
00460   if(X509_verify(m_pCert, pubKey) == 1)
00461   {
00462     CAMsg::printMsg(LOG_DEBUG, "Successfully verified certificate.\n");
00463     return E_SUCCESS;
00464   }
00465   CAMsg::printMsg(LOG_ERR, "Verification Error: Signature is not correct!\n");
00466   return E_UNKNOWN;
00467 }
00468 
00469 bool CACertificate::isValid() const
00470 {
00471   ASN1_TIME* pValidNotBefore=X509_get_notBefore(m_pCert);
00472   ASN1_TIME* pValidNotAfter=X509_get_notAfter(m_pCert);
00473   if(X509_cmp_current_time( pValidNotBefore) <0 
00474       && X509_cmp_current_time(pValidNotAfter) >0)
00475   {
00476     return true;
00477   }
00478   //check if certificate is valid within grace period of two months
00479   time_t now = time(NULL);    //get current time;
00480   tm* time = new tm;
00481   time = gmtime_r(&now, time);  //convert time to modifiable format
00482   if(time->tm_mon < 2)      //go back two months in time
00483   {
00484     time->tm_mon = time->tm_mon+10;
00485     time->tm_year = time->tm_year-1;
00486   }
00487   else
00488   {
00489     time->tm_mon = time->tm_mon-2;
00490   }
00491   time_t ttiq  = mktime(time);    //convert time back to time_t and check again
00492   delete time;
00493   time = NULL;
00494   if(X509_cmp_time( pValidNotBefore, &ttiq) <0
00495       && X509_cmp_time(pValidNotAfter, &ttiq) >0)
00496   {
00497     CAMsg::printMsg(LOG_WARNING, "Certificate is only valid within grace period of two months!\n");
00498     return true;
00499   }
00500   return false;
00501 }
00502 
00503 #endif //ONLY_LOCAL_PROXY
00504