⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 security.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 5 页
字号:

   Data bodyData;
   DataStream strm(bodyData);
   bodyIn->encodeHeaders(strm);
   bodyIn->encode( strm );
   strm.flush();

   InfoLog( << "body data to encrypt is <" << bodyData.escaped() << ">" );

   const char* p = bodyData.data();
   int s = bodyData.size();

   BIO* in = BIO_new_mem_buf( (void*)p,s);
   assert(in);
   DebugLog( << "created in BIO");

   BIO* out = BIO_new(BIO_s_mem());
   assert(out);
   DebugLog( << "created out BIO" );

   InfoLog( << "target cert name is <" << recipCertName << ">" );
   if (mUserCerts.count(recipCertName) == 0)
   {
      BIO_free(in);
      BIO_free(out);
      WarningLog (<< "Tried to encrypt with no cert or private key for " << recipCertName);
      throw Exception("No cert or private key to encrypt with",__FILE__,__LINE__);
   }

   X509* cert = mUserCerts[recipCertName];
   assert(cert);

   STACK_OF(X509) *certs = sk_X509_new_null();
   assert(certs);
   sk_X509_push(certs, cert);

// if you think you need to change the following few lines, please email fluffy
// the value of OPENSSL_VERSION_NUMBER ( in opensslv.h ) and the signature of
// PKCS_encrypt found ( in pkcs7.h ) and the OS you are using
#if (  OPENSSL_VERSION_NUMBER > 0x009060ffL )
//   const EVP_CIPHER* cipher =  EVP_des_ede3_cbc();
   const EVP_CIPHER* cipher =  EVP_aes_128_cbc(); 
#else
   //const EVP_CIPHER* cipher = EVP_enc_null();
   EVP_CIPHER* cipher =  EVP_des_ede3_cbc();
#endif
   assert( cipher );

#if (OPENSSL_VERSION_NUMBER < 0x0090705fL )
#warning PKCS7_encrypt() is broken in OpenSSL 0.9.7d
#endif

   PKCS7* pkcs7 = PKCS7_encrypt( certs, in, cipher, flags);
   if ( !pkcs7 )
   {
      BIO_free(in);
      BIO_free(out);
      sk_X509_free(certs);
      ErrLog( << "Error creating PKCS7 encrypt object" );
      //throw Exception("Can't encrypt",__FILE__,__LINE__);
      return 0;
   }
   DebugLog( << "created PKCS7 encrypt object " );

   i2d_PKCS7_bio(out,pkcs7);

   BIO_flush(out);

   char* outBuf=0;
   long size = BIO_get_mem_data(out,&outBuf);
   assert( size > 0 );

   Data outData(outBuf,size);
   assert( (long)outData.size() == size );

   InfoLog( << "Encrypted body size is " << outData.size() );
   InfoLog( << "Encrypted body is <" << outData.escaped() << ">" );

   static char RESIP_ENCRYPT_OUT[] = "resip-encrypt-out";
   Security::dumpAsn(RESIP_ENCRYPT_OUT, outData);

   Pkcs7Contents* outBody = new Pkcs7Contents( outData );
   assert( outBody );

   outBody->header(h_ContentType).param( p_smimeType ) = "enveloped-data";
   outBody->header(h_ContentType).param( p_name ) = "smime.p7m";
   outBody->header(h_ContentDisposition).param( p_handling ) = "required";
   outBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7";
   outBody->header(h_ContentDisposition).value() =  "attachment" ;
   outBody->header(h_ContentTransferEncoding).value() = "binary";

   BIO_free(in);
   BIO_free(out);
   sk_X509_free(certs);

   return outBody;
}


MultipartSignedContents *
BaseSecurity::signAndEncrypt( const Data& senderAor, Contents* body, const Data& recipCertName )
{
   //assert(0);
   //return 0;
   return sign(senderAor, encrypt(body, recipCertName));
}


Data
BaseSecurity::computeIdentity( const Data& signerDomain, const Data& in ) const
{
   DebugLog( << "Compute identity for " << in );

   if (mDomainPrivateKeys.count(signerDomain) == 0)
   {
      InfoLog( << "No private key for " << signerDomain );
      throw Exception("Missing private key when computing identity",__FILE__,__LINE__);
   }

   EVP_PKEY* pKey = mDomainPrivateKeys[signerDomain];
   assert( pKey );
 
   if ( pKey->type !=  EVP_PKEY_RSA )
   {
      ErrLog( << "Private key (type=" << pKey->type <<"for " 
              << signerDomain << " is not of type RSA" );
      throw Exception("No RSA private key when computing identity",__FILE__,__LINE__);
   }

   assert( pKey->type ==  EVP_PKEY_RSA );
   RSA* rsa = EVP_PKEY_get1_RSA(pKey);

   unsigned char result[4096];
   int resultSize = sizeof(result);
   assert( resultSize >= RSA_size(rsa) );

   SHA1Stream sha;
   sha << in;
   Data hashRes =  sha.getBin();
   DebugLog( << "hash of string is 0x" << hashRes.hex() );

#if 1
   int r = RSA_sign(NID_sha1, (unsigned char *)hashRes.data(), hashRes.size(),
                    result, (unsigned int*)( &resultSize ),
            rsa);
   assert( r == 1 );
#else
   resultSize = RSA_private_encrypt(hashResLen, hashRes,
                                    result, rsa, RSA_PKCS1_PADDING);
   if ( resultSize == -1 )
   {
      DebugLog( << "Problem doing RSA encrypt for identity");
      while (1)
      {
         const char* file;
         int line;

         unsigned long code = ERR_get_error_line(&file,&line);
         if ( code == 0 )
         {
            break;
         }

         char buf[256];
         ERR_error_string_n(code,buf,sizeof(buf));
         ErrLog( << buf  );
         InfoLog( << "Error code = " << code << " file="<<file<<" line=" << line );
      }

      return Data::Empty;
   }
#endif

   Data res(result,resultSize);
   DebugLog( << "rsa encrypt of hash is 0x"<< res.hex() );

   Data enc = res.base64encode();

   static char IDENTITY_IN[] = "identity-in";
   static char IDENTITY_IN_HASH[] = "identity-in-hash";
   static char IDENTITY_IN_RSA[] = "identity-in-rsa";
   static char IDENTITY_IN_BASE64[] = "identity-in-base64";

   Security::dumpAsn(IDENTITY_IN, in );
   Security::dumpAsn(IDENTITY_IN_HASH, hashRes );
   Security::dumpAsn(IDENTITY_IN_RSA,res);
   Security::dumpAsn(IDENTITY_IN_BASE64,enc);

   return enc;
}


bool
BaseSecurity::checkIdentity( const Data& signerDomain, const Data& in, const Data& sigBase64, X509* pCert ) const
{
   X509* cert =  pCert;
   if (!cert)
   {
      if (mDomainCerts.count(signerDomain) == 0)
      {
         ErrLog( << "No public key for " << signerDomain );
         throw Exception("Missing public key when verifying identity",__FILE__,__LINE__);
      }
      cert = mDomainCerts[signerDomain];
   }
   
   DebugLog( << "Check identity for " << in );
   DebugLog( << " base64 data is " << sigBase64 );

   Data sig = sigBase64.base64decode();
   DebugLog( << "decoded sig is 0x"<< sig.hex() );

   SHA1Stream sha;
   sha << in;
   Data hashRes =  sha.getBin();
   DebugLog( << "hash of string is 0x" << hashRes.hex() );

   EVP_PKEY* pKey = X509_get_pubkey( cert );
   assert( pKey );

   assert( pKey->type ==  EVP_PKEY_RSA );
   RSA* rsa = EVP_PKEY_get1_RSA(pKey);

#if 1
   int ret = RSA_verify(NID_sha1, (unsigned char *)hashRes.data(),
                        hashRes.size(), (unsigned char*)sig.data(), sig.size(),
                        rsa);
#else
   unsigned char result[4096];
   int resultSize = sizeof(result);
   assert( resultSize >= RSA_size(rsa) );

   resultSize = RSA_public_decrypt(sig.size(),(unsigned char*)sig.data(),
                                   result, rsa, RSA_PKCS1_PADDING );
   assert( resultSize != -1 );
   //assert( resultSize == SHA_DIGEST_LENGTH );
   Data recievedHash(result,resultSize);
   dumpAsn("identity-out-decrypt", recievedHash );

   bool ret =  ( computedHash == recievedHash );
#endif

   DebugLog( << "rsa verify result is " << ret  );

   static char IDENTITY_OUT_MSG[] = "identity-out-msg";
   static char IDENTITY_OUT_BASE64[] = "identity-out-base64";
   static char IDENTITY_OUT_SIG[] = "identity-out-sig";
   static char IDENTITY_OUT_HASH[] = "identity-out-hash";

   Security::dumpAsn(IDENTITY_OUT_MSG, in );
   Security::dumpAsn(IDENTITY_OUT_BASE64,sigBase64);
   Security::dumpAsn(IDENTITY_OUT_SIG, sig);
   Security::dumpAsn(IDENTITY_OUT_HASH, hashRes );

   return (ret != 0);
}


void
BaseSecurity::checkAndSetIdentity( const SipMessage& msg, const Data& certDer) const
{
   auto_ptr<SecurityAttributes> sec(new SecurityAttributes);
   X509* cert=NULL;
   
   try
   {
      if ( !certDer.empty() )
      {
#if (OPENSSL_VERSION_NUMBER < 0x0090800fL )
         unsigned char* in = (unsigned char*)certDer.data();
#else
         unsigned const char* in = (unsigned const char*)certDer.data();
#endif
         if (d2i_X509(&cert,&in,certDer.size()) == 0)
         {
            DebugLog(<< "Could not read DER certificate from " << certDer );
            cert = NULL;
         }
      }
      if ( certDer.empty() || cert )
      {
         if ( checkIdentity(msg.header(h_From).uri().host(),
                            msg.getCanonicalIdentityString(),
                            msg.header(h_Identity).value(),
                            cert ) )
         {
            sec->setIdentity(msg.header(h_From).uri().getAor());
            sec->setIdentityStrength(SecurityAttributes::Identity);
         }
         else
         {
            sec->setIdentity(msg.header(h_From).uri().getAor());
            sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
         }
      }
      else
      {
         sec->setIdentity(msg.header(h_From).uri().getAor());
         sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
      }
   }
   catch (BaseException&)
   {
      sec->setIdentity(msg.header(h_From).uri().getAor());
      sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
   }
   msg.setSecurityAttributes(sec);
}


Contents*
BaseSecurity::decrypt( const Data& decryptorAor, const Pkcs7Contents* contents)
{

   DebugLog( << "decryptor Aor: <" << decryptorAor << ">" );

   int flags=0;
   flags |= PKCS7_BINARY;

   // for now, assume that this is only a singed message
   assert( contents );

   Data text = contents->getBodyData();
   DebugLog( << "uncode body = <" << text.escaped() << ">" );
   DebugLog( << "uncode body size = " << text.size() );

   static char RESIP_ASN_DECRYPT[] = "resip-asn-decrypt";
   Security::dumpAsn(RESIP_ASN_DECRYPT, text );

   BIO* in = BIO_new_mem_buf( (void*)text.c_str(), text.size());
   assert(in);
   InfoLog( << "created in BIO");

   BIO* out;
   out = BIO_new(BIO_s_mem());
   assert(out);
   InfoLog( << "created out BIO" );

   PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0);
   if ( !pkcs7 )
   {
      ErrLog( << "Problems doing decode of PKCS7 object" );

      while (1)
      {
         const char* file;
         int line;

         unsigned long code = ERR_get_error_line(&file,&line);
         if ( code == 0 )
         {
            break;
         }

         char buf[256];
         ERR_error_string_n(code,buf,sizeof(buf));
         ErrLog( << buf  );
         InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
      }

      BIO_free(in);
      BIO_free(out);

      return 0;
   }
   BIO_flush(in);

   int type=OBJ_obj2nid(pkcs7->type);
   switch (type)
   {
      case NID_pkcs7_signed:
         InfoLog( << "data is pkcs7 signed" );
         break;
      case NID_pkcs7_signedAndEnveloped:
         InfoLog( << "data is pkcs7 signed and enveloped" );
         break;
      case NID_pkcs7_enveloped:
         InfoLog( << "data is pkcs7 enveloped" );
         break;
      case NID_pkcs7_data:
         InfoLog( << "data i pkcs7 data" );
         break;
      case NID_pkcs7_encrypted:
         InfoLog( << "data is pkcs7 encrypted " );
         break;
      case NID_pkcs7_digest:
         InfoLog( << "data is pkcs7 digest" );
         break;
      default:
         InfoLog( << "Unkown pkcs7 type" );
         break;
   }

   STACK_OF(X509)* certs = sk_X509_new_null();
   assert( certs );

   //   flags |= PKCS7_NOVERIFY;

   assert( mRootTlsCerts );

   switch (type)
   {
      case NID_pkcs7_signedAndEnveloped:
      {
         BIO_free(in);
         BIO_free(out);
         sk_X509_free(certs);
         throw Exception("Signed and enveloped is not supported", __FILE__, __LINE__);
      }
      break;

      case NID_pkcs7_enveloped:
      {
         if (mUserPrivateKeys.count(decryptorAor) == 0)
         {
            BIO_free(in);
            BIO_free(out);
            sk_X509_free(certs);
            InfoLog( << "Don't have a private key for " << decryptorAor << " for  PKCS7_decrypt" );
            throw Exception("Missing private key", __FILE__, __LINE__);
         }
         else if (mUserCerts.count(decryptorAor) == 0)
         {
            BIO_free(in);
            BIO_free(out);
            sk_X509_free(certs);
            InfoLog( << "Don't have a public cert for " << decryptorAor << " for  PKCS7_decrypt" );
            throw Exception("Missing cert", __FILE__, __LINE__);
         }

         EVP_PKEY* privateKey = mUserPrivateKeys[decryptorAor];
         X509* publicCert = mUserCerts[decryptorAor];

         if ( PKCS7_decrypt(pkcs7, privateKey, publicCert, out, flags ) != 1 )
         {
            ErrLog( << "Problems doing PKCS7_decrypt" );
            while (1)
            {
               const char* file;
               int line;

               unsigned long code = ERR_get_error_line(&file,&line);
               if ( code == 0 )
               {
                  break;
               }

               char buf[256];
               ERR_error_string_n(code,buf,sizeof(buf));
               ErrLog( << buf  );
               InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
            }

            BIO_free(in);
            BIO_free(out);
            sk_X509_free(certs);
            return 0;
         }
      }
      break;

      default:
         BIO_free(in);
         BIO_free(out);
         sk_X509_free(certs);
         ErrLog(<< "Got PKCS7 data that could not be handled type=" << type );
         throw Exception("Unsupported PKCS7 data type", __FILE__, __LINE__);
   }

   BIO_flush(out);   
   BUF_MEM* bufMem;
   BIO_get_mem_ptr(out, &bufMem);

   int len = bufMem->length;
   char* buffer = new char[len];
   memcpy(buffer, bufMem->data, len);

   BIO_set_close(out, BIO_CLOSE);
   BIO_free(in);
   BIO_free(out);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -