Mixe for Privacy and Anonymity in the Internet
CACertificate.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2000, The JAP-Team
3 All rights reserved.
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6 
7  - Redistributions of source code must retain the above copyright notice,
8  this list of conditions and the following disclaimer.
9 
10  - Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation and/or
12  other materials provided with the distribution.
13 
14  - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
15  may be used to endorse or promote products derived from this software without specific
16  prior written permission.
17 
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
20 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
27 */
28 
29 #include "StdAfx.h"
30 #if !defined ONLY_LOCAL_PROXY || defined INCLUDE_MIDDLE_MIX
31 #include "CACertificate.hpp"
32 #include "CABase64.hpp"
33 #include "CAUtil.hpp"
34 #include "CAMsg.hpp"
35 
37 
39  {
40  m_pCert = NULL;
41  m_pSKI = NULL;
42  m_pAKI = NULL;
43  }
44 
46  {
47  m_pCert = x;
48  m_pSKI = NULL;
49  m_pAKI = NULL;
50  if(m_pCert != NULL)
51  {
52  m_pSKI = (ASN1_OCTET_STRING*) X509_get_ext_d2i(m_pCert, NID_subject_key_identifier, NULL, NULL);
53  m_pAKI = (AUTHORITY_KEYID*) X509_get_ext_d2i (m_pCert, NID_authority_key_identifier, NULL, NULL);
54  }
55  }
65 {
66  SINT32 ret = E_UNKNOWN;
67  ASN1_OCTET_STRING* skid = NULL;
68 
69  skid = ASN1_OCTET_STRING_new();
70  if(NULL == skid) goto end;
71 
72  ASN1_OCTET_STRING_set(skid, a_value, a_valueLen);
73  if( X509_add1_ext_i2d(m_pCert, NID_subject_key_identifier, skid, false, X509V3_ADD_REPLACE) == 1)
74  {
75  m_pSKI = skid;
76  ret = E_SUCCESS;
77  }
78 
79 end:
80  //ASN1_OCTET_STRING_free(skid);
81  return ret;
82 }
83 
84 
85 CACertificate* CACertificate::decode(const DOMNode* n,UINT32 type,const char* passwd)
86  {
87  const DOMNode* node=n;
88  switch(type)
89  {
90  case CERT_PKCS12:
91  while(node!=NULL)
92  {
93  if(equals(node->getNodeName(),"X509PKCS12"))
94  {
95  UINT32 strLen=4096;
96  UINT8* tmpStr=new UINT8[strLen];
97  CACertificate* cert=NULL;
98  if(getDOMElementValue(node,tmpStr,&strLen)!=E_SUCCESS)
99  {
100  delete[] tmpStr;
101  tmpStr = NULL;
102  return NULL;
103  }
104  UINT32 decLen=4096;
105  UINT8* decBuff=new UINT8[decLen];
106  SINT32 ret=CABase64::decode((UINT8*)tmpStr,strLen,decBuff,&decLen);
107  delete[] tmpStr;
108  tmpStr = NULL;
109  if(ret==E_SUCCESS)
110  {
111  cert=decode(decBuff,decLen,CERT_PKCS12,passwd);
112  }
113  delete[] decBuff;
114  decBuff = NULL;
115  return cert;
116  }
117  node=node->getNextSibling();
118  }
119  break;
121  while(node!=NULL)
122  {
123  if(equals(node->getNodeName(),"X509Certificate"))
124  {
125  UINT32 strLen=4096;
126  UINT8* tmpStr=new UINT8[strLen];
127  CACertificate* cert=NULL;
128  if(getDOMElementValue(node,tmpStr,&strLen)!=E_SUCCESS)
129  {
130  delete[] tmpStr;
131  tmpStr = NULL;
132  return NULL;
133  }
134  UINT32 decLen=4096;
135  UINT8* decBuff=new UINT8[decLen];
136  SINT32 ret=CABase64::decode((UINT8*)tmpStr,strLen,decBuff,&decLen);
137  delete[] tmpStr;
138  tmpStr = NULL;
139  if(ret==E_SUCCESS)
140  {
141  cert=decode(decBuff,decLen,CERT_DER);
142  }
143  delete[] decBuff;
144  decBuff = NULL;
145  return cert;
146  }
147  node=node->getNextSibling();
148  }
149 
150  }
151  return NULL;
152  }
153 
154 CACertificate* CACertificate::decode(const UINT8* const buff,UINT32 bufflen,UINT32 type,const char* const passwd)
155  {
156  if(buff==NULL)
157  return NULL;
158  X509* tmpCert=NULL;
159  EVP_PKEY* tmpKey=NULL;
160  SINT32 ret=-1;
161  const UINT8* tmp=buff;
162  switch(type)
163  {
164  case CERT_DER:
165  tmp=buff;
166  #if OPENSSL_VERSION_NUMBER > 0x009070CfL
167  tmpCert=d2i_X509(NULL,&tmp,bufflen);
168  #else
169  tmpCert=d2i_X509(NULL,(UINT8**)&tmp,bufflen);
170  #endif
171  break;
172  case CERT_PKCS12:
173  PKCS12* tmpPKCS12;
174  #if OPENSSL_VERSION_NUMBER > 0x009070CfL
175  tmpPKCS12=d2i_PKCS12(NULL,&tmp,bufflen);
176  #else
177  tmpPKCS12=d2i_PKCS12(NULL,(UINT8**)&tmp,bufflen);
178  #endif
179  /*Note: Basically we are not interested in the private keys here - but still we need cannot supply
180  *NULL for that parameter, as OpenSSL 1.0.0. would not work in that case*/
181  ret=PKCS12_parse(tmpPKCS12,passwd,&tmpKey,&tmpCert,NULL);
182  PKCS12_free(tmpPKCS12);
183  EVP_PKEY_free(tmpKey);
184  if(ret!=1)
185  {
186  return NULL;
187  }
188  break;
190  XERCES_CPP_NAMESPACE::DOMDocument* doc=parseDOMDocument(buff,bufflen);
191  if(doc == NULL)
192  {
193  return NULL;
194  }
195  DOMElement* root=doc->getDocumentElement();
196  if(root==NULL||!equals(root->getNodeName(),"X509Certificate"))
197  {
198  return NULL;
199  }
200  UINT8* tmpBuff=new UINT8[bufflen];
201  UINT32 tmpBuffSize=bufflen;
202  if(getDOMElementValue(root,tmpBuff,&tmpBuffSize)==E_SUCCESS)
203  {
204  ret=CABase64::decode(tmpBuff,tmpBuffSize,tmpBuff,&tmpBuffSize);
205  }
206  tmp=tmpBuff;
207  if(ret==E_SUCCESS)
208  {
209  #if OPENSSL_VERSION_NUMBER > 0x009070CfL
210  tmpCert=d2i_X509(NULL,&tmp,tmpBuffSize);
211  #else
212  tmpCert=d2i_X509(NULL,(UINT8**)&tmp,tmpBuffSize);
213  #endif
214  }
215  delete[] tmpBuff;
216  tmpBuff = NULL;
217  break;
218  }
219  if(tmpCert == NULL)
220  {
221  return NULL;
222  }
223  return new CACertificate(tmpCert);
224  }
225 
227  {
228  if(m_pCert==NULL||buff==NULL||bufflen==NULL)
229  return E_UNKNOWN;
230  int i=0;
231  UINT8* tmp=buff;
232  switch(type)
233  {
234  case CERT_DER:
235  i=i2d_X509(m_pCert,&tmp);
236  if(i==0)
237  return E_UNKNOWN;
238  *bufflen=i;
239  break;
241  #define X509_CERTIFICATE_TAGNAME_LEN 17
242  memcpy(buff,"<X509Certificate>",X509_CERTIFICATE_TAGNAME_LEN); //we start with '<X509Certificate>'
244  i=i2d_X509(m_pCert,&tmp); //now we need DER
245  if(i==0)
246  return E_UNKNOWN;
248  buff+X509_CERTIFICATE_TAGNAME_LEN,bufflen); //now we have it converted to Base64
249  memcpy( buff+X509_CERTIFICATE_TAGNAME_LEN+*bufflen,
250  "</X509Certificate>",X509_CERTIFICATE_TAGNAME_LEN+1); //we end it with '</X509Certificate>'
251  *bufflen+=2*X509_CERTIFICATE_TAGNAME_LEN+1;
252  break;
253  default:
254  return E_UNKNOWN;
255  }
256  return E_SUCCESS;
257  }
258 
259 SINT32 CACertificate::encode(DOMElement* & elemRoot,XERCES_CPP_NAMESPACE::DOMDocument* doc) const
260  {
261  elemRoot=createDOMElement(doc,"X509Certificate");
262  UINT8 buff[2048]; //TODO: Very bad --> looks like easy buffer overflow... [donn't care at the moment...]
263  UINT8* tmp=buff;
264  int i=i2d_X509(m_pCert,&tmp); //now we need DER
265  UINT32 bufflen=2048;
266  CABase64::encode(buff,i,buff,&bufflen); //now we have it converted to Base64
267  buff[bufflen]=0;
268  setDOMElementValue(elemRoot,buff);
269  return E_SUCCESS;
270  }
271 
281 {
282  if (m_pSKI == NULL)
283  {
284 #ifdef DEBUG
285  CAMsg::printMsg( LOG_ERR, "Unable to get SKI from Certificate, trying to recover\n");
286 #endif
288  if(m_pSKI == NULL)
289  {
290  CAMsg::printMsg( LOG_ERR, "Unable to retrieve 1SKI from Certificate\n");
291  return E_UNKNOWN;
292  }
293 #ifdef DEBUG
294  else
295  {
296  CAMsg::printMsg( LOG_ERR, "Recovery SUCCESSFUL!\n");
297  }
298 #endif
299  }
300  // Get the ASCII string format of the subject key identifier
301  UINT8* cSki = (UINT8*)i2s_ASN1_OCTET_STRING( NULL, m_pSKI );
302  if ( cSki==NULL )
303  {
304  CAMsg::printMsg( LOG_ERR, "Unable to convert SKI\n");
305  return E_UNKNOWN;
306  }
307 #ifdef DEBUG
308  CAMsg::printMsg( LOG_ERR, "getSubjectKeyIdentifier: SKI is %s\n", cSki);
309 #endif
310  removeColons(cSki, strlen((const char*)cSki), r_ski, r_skiLen);
311  OPENSSL_free(cSki);
312  return E_SUCCESS;
313 }
314 
322 {
323  UINT32 len = 0;
324  UINT8 sha_hash[SHA_DIGEST_LENGTH];
325  X509_pubkey_digest(m_pCert, EVP_sha1(), sha_hash, &len);
326  return setSubjectKeyIdentifier( sha_hash, len );
327 }
328 
341 SINT32 CACertificate::removeColons(const UINT8* a_cSkid, UINT32 a_cSkidLen, UINT8 *&r_ski, UINT32 *r_skiLen)
342 {
343  UINT32 i = 0, j = 0;
344  UINT32 tmp = (2*a_cSkidLen)/3 + 2;
345  if(*r_skiLen < tmp)
346  {
347  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);
348  return E_UNKNOWN;
349  }
350  for(i = 0; i < a_cSkidLen; i++)
351  {
352  if(i % 3 == 2) {
353  j++;
354  continue;
355  }
356  r_ski[i-j] = a_cSkid[i];
357  }
358  r_ski[i-j] = 0;
359  *r_skiLen = i-j;
360  return E_SUCCESS;
361 }
362 
364 {
365  if(a_cert == NULL || a_cert->m_pCert == NULL || m_pCert == NULL)
366  {
367  return E_UNKNOWN;
368  }
369  //check validity
370  if(!isValid())
371  {
372  CAMsg::printMsg(LOG_ERR, "Verification Error: Certificate is not valid!\n");
373  return E_UNKNOWN;
374  }
375  //namechaining...
376  if(X509_NAME_cmp(X509_get_issuer_name(m_pCert), X509_get_subject_name(a_cert->m_pCert)) != 0)
377  {
378  CAMsg::printMsg(LOG_ERR, "Verification Error: Names do not match!\n");
379  return E_UNKNOWN;
380  }
381  //keychaining... (only if available)
382  if(m_pAKI != NULL && a_cert->m_pSKI != NULL)
383  {
384  if(ASN1_OCTET_STRING_cmp(m_pAKI->keyid, a_cert->m_pSKI) != 0)
385  {
386  CAMsg::printMsg(LOG_ERR, "Verification Error: Key Identifiers do not match!\n");
387  return E_UNKNOWN;
388  }
389  }
390  //get public key
391  EVP_PKEY* pubKey = X509_get_pubkey(a_cert->m_pCert);
392  if(pubKey == NULL)
393  {
394  CAMsg::printMsg(LOG_ERR, "Verification Error: Public Key is NULL!\n");
395  return E_UNKNOWN;
396  }
397  //check if public key and signature algorithm match -> does not work because of openssl bug!
398  //SINT32 sigType = X509_get_signature_type(m_pCert);
399  /*SINT32 sigType = OBJ_obj2nid((m_pCert)->sig_alg->algorithm);
400  SINT32 keyType = EVP_PKEY_type(pubKey->type);
401  CAMsg::printMsg(LOG_DEBUG, "sigType is %d and keyType is %d\n", sigType, keyType);
402  if((sigType != (NID_dsaWithSHA1 || NID_sha1WithRSAEncryption ||NID_ecdsa_with_SHA1))
403  && keyType != EVP_PKEY_DSA) ||
404  (sigType == NID_sha1WithRSAEncryption && keyType != EVP_PKEY_RSA) ||
405  (sigType == NID_ecdsa_with_SHA1 && keyType != EVP_PKEY_EC))
406  {
407  CAMsg::printMsg(LOG_ERR, "Verification Error: Signature Algorithm does not match!\n");
408  //return E_UNKNOWN;
409  }*/
410  SINT32 ret = X509_verify(m_pCert, pubKey);
411  if(ret == 1)
412  {
413  CAMsg::printMsg(LOG_DEBUG, "Successfully verified certificate.\n");
414  return E_SUCCESS;
415  }
416  CAMsg::printMsg(LOG_ERR, "Verification Error: Signature is not correct!\n");
417  return E_UNKNOWN;
418 }
419 
421 {
422 #ifdef __BUILD_AS_SHADOW_PLUGIN__
423 //if the build the Mix as a plugin for the shadow simulator, we do not test certificate validity, because
424 //the shadow simulator uses it own time base make this checks kind of usesless / break the simulation
425 return true;
426 
427 #endif //D__BUILD_AS_SHADOW_PLUGIN__
428 #if OPENSSL_VERSION_NUMBER > 0x100020cfL
429  const ASN1_TIME* pValidNotBefore=X509_get0_notBefore(m_pCert);
430  const ASN1_TIME* pValidNotAfter=X509_get0_notAfter(m_pCert);
431 #else
432  ASN1_TIME* pValidNotBefore=X509_get_notBefore(m_pCert);
433  ASN1_TIME* pValidNotAfter=X509_get_notAfter(m_pCert);
434 #endif
435  if(X509_cmp_current_time( pValidNotBefore) <0 && X509_cmp_current_time(pValidNotAfter) >0)
436  {
437  return true;
438  }
439  //check if certificate is valid within grace period of two months
440  time_t now = time(NULL); //get current time;
441  tm* time = new tm;
442  time = gmtime_r(&now, time); //convert time to modifiable format
443  if(time->tm_mon < 2) //go back two months in time
444  {
445  time->tm_mon = time->tm_mon+10;
446  time->tm_year = time->tm_year-1;
447  }
448  else
449  {
450  time->tm_mon = time->tm_mon-2;
451  }
452  time_t ttiq = mktime(time); //convert time back to time_t and check again
453  delete time;
454  time = NULL;
455  if(X509_cmp_time( pValidNotBefore, &ttiq) <0 && X509_cmp_time(pValidNotAfter, &ttiq) >0)
456  {
457  CAMsg::printMsg(LOG_WARNING, "Certificate is only valid within grace period of two months!\n");
458  return true;
459  }
460  return false;
461 }
462 
464 {
465  if (m_pSKI == NULL)
466  {
468  if(m_pSKI == NULL)
469  {
470  CAMsg::printMsg( LOG_ERR, "Unable to retrieve raw SKI from Certificate\n");
471  return E_UNKNOWN;
472  }
473 
474  }
475  if(*r_skiLen < (UINT32) m_pSKI->length)
476  {
477  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 );
478  return E_UNKNOWN;
479  }
480  *r_skiLen = m_pSKI->length;
481  for(SINT32 i=0; i<m_pSKI->length; i++)
482  {
483  r_ski[i] = m_pSKI->data[i];
484  }
485  return E_SUCCESS;
486 }
487 
489 {
490  if(m_pAKI == NULL)
491  {
492  return E_UNKNOWN;
493  }
494 
495  ASN1_OCTET_STRING* pKeyID = NULL;
496  pKeyID = m_pAKI->keyid;
497  if(pKeyID == NULL)
498  {
499  return E_UNKNOWN;
500  }
501 
502  // Get the ASCII string format of the authority key identifier
503  UINT8* cKeyID = (UINT8*)i2s_ASN1_OCTET_STRING(NULL, pKeyID);
504  if (cKeyID == NULL)
505  {
506  return E_UNKNOWN;
507  }
508  removeColons(cKeyID, strlen((const char*)cKeyID), r_aki, r_akiLen);
509  OPENSSL_free(cKeyID);
510  return E_SUCCESS;
511 }
512 
513 
514 #endif //ONLY_LOCAL_PROXY
515 
#define X509_CERTIFICATE_TAGNAME_LEN
#define CERT_PKCS12
#define CERT_DER
#define CERT_X509CERTIFICATE
#define CERT_XML_X509CERTIFICATE
SINT32 getDOMElementValue(const DOMNode *const pElem, UINT8 *value, UINT32 *valuelen)
Returns the content of the text node(s) under elem as null-terminated C String.
Definition: CAUtil.cpp:746
SINT32 setDOMElementValue(DOMElement *pElem, SINT32 value)
Definition: CAUtil.cpp:939
bool equals(const XMLCh *const e1, const char *const e2)
Definition: CAUtil.cpp:645
XERCES_CPP_NAMESPACE::DOMDocument * parseDOMDocument(const UINT8 *const buff, UINT32 len)
Parses a buffer containing an XML document and returns this document.
Definition: CAUtil.cpp:663
DOMElement * createDOMElement(XERCES_CPP_NAMESPACE::DOMDocument *pOwnerDoc, const char *const name)
Creates a new DOMElement with the given name which belongs to the DOMDocument owernDoc.
Definition: CAUtil.cpp:814
signed int SINT32
Definition: basetypedefs.h:132
unsigned char UINT8
Definition: basetypedefs.h:135
unsigned int UINT32
Definition: basetypedefs.h:131
static SINT32 encode(const UINT8 *in, UINT32 len, UINT8 *out, UINT32 *outlen)
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff...
Definition: CABase64.cpp:102
static SINT32 decode(const UINT8 *in, UINT32 len, UINT8 *out, UINT32 *outlen)
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff...
Definition: CABase64.cpp:41
SINT32 encode(UINT8 *buff, UINT32 *bufflen, UINT32 type) const
AUTHORITY_KEYID * m_pAKI
static UINT8 * m_spXmlElementName
SINT32 getAuthorityKeyIdentifier(UINT8 *r_aki, UINT32 *r_akiLen) const
SINT32 setSubjectKeyIdentifier()
LERNGRUPPE Sets the subjectKeyIdentifier extension for this certificate to the hash of the public key...
bool isValid() const
SINT32 verify(const CACertificate *a_cert) const
SINT32 getSubjectKeyIdentifier(UINT8 *r_ski, UINT32 *r_skiLen)
LERNGRUPPE Accessor method for the subjectKeyIdentifier (SKI) extension stored in this certificate.
static SINT32 removeColons(const UINT8 *a_cSki, UINT32 a_cSkiLen, UINT8 *&r_ski, UINT32 *r_skiLen)
LERNGRUPPE Removes the colons from the string representation of the given SKI.
SINT32 getRawSubjectKeyIdentifier(UINT8 *r_ski, UINT32 *r_skiLen)
static CACertificate * decode(const UINT8 *const buff, UINT32 bufflen, UINT32 type, const char *const passwd=NULL)
Extracts a certificate from an encoded (DER,XML) form.
ASN1_OCTET_STRING * m_pSKI
static SINT32 printMsg(UINT32 typ, const char *format,...)
Writes a given message to the log.
Definition: CAMsg.cpp:251
const SINT32 E_SUCCESS
Definition: errorcodes.hpp:2
#define E_UNKNOWN
Definition: errorcodes.hpp:3
UINT8 type
Definition: typedefs.hpp:1
UINT16 len
Definition: typedefs.hpp:0