You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by sc...@apache.org on 2016/12/16 22:42:57 UTC

svn commit: r1774677 - in /santuario/xml-security-cpp/trunk: Projects/VC10.0/xsec/xsec_lib/ xsec/enc/OpenSSL/

Author: scantor
Date: Fri Dec 16 22:42:56 2016
New Revision: 1774677

URL: http://svn.apache.org/viewvc?rev=1774677&view=rev
Log:
OpenSSL 1.1 compatibility - Make DSA_SIG-ECDSA-EVP opaque

Modified:
    santuario/xml-security-cpp/trunk/Projects/VC10.0/xsec/xsec_lib/xsec_lib.vcxproj
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoProvider.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.cpp
    santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.hpp

Modified: santuario/xml-security-cpp/trunk/Projects/VC10.0/xsec/xsec_lib/xsec_lib.vcxproj
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/Projects/VC10.0/xsec/xsec_lib/xsec_lib.vcxproj?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/Projects/VC10.0/xsec/xsec_lib/xsec_lib.vcxproj (original)
+++ santuario/xml-security-cpp/trunk/Projects/VC10.0/xsec/xsec_lib/xsec_lib.vcxproj Fri Dec 16 22:42:56 2016
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug No Xalan|Win32">
@@ -797,4 +797,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.cpp Fri Dec 16 22:42:56 2016
@@ -105,7 +105,7 @@ void OpenSSLCryptoKeyDSA::setPBase(BIGNU
 
 #else
     // Save it for later
-    if (mp_accumP == NULL)
+    if (mp_accumP != NULL)
         BN_free(mp_accumP);
 
     mp_accumP = p;
@@ -132,7 +132,7 @@ void OpenSSLCryptoKeyDSA::setQBase(BIGNU
     mp_dsaKey->q = q;
 
 #else
-    if (mp_accumQ == NULL)
+    if (mp_accumQ != NULL)
         BN_free(mp_accumQ);
 
     mp_accumQ = q;
@@ -159,7 +159,7 @@ void OpenSSLCryptoKeyDSA::setGBase(BIGNU
     mp_dsaKey->g = g;
 
 #else
-    if (mp_accumG == NULL)
+    if (mp_accumG != NULL)
         BN_free(mp_accumG);
 
     mp_accumG = g;
@@ -212,6 +212,9 @@ OpenSSLCryptoKeyDSA::OpenSSLCryptoKeyDSA
     // Create a new key to be loaded as we go
 
     mp_dsaKey = DSA_new();
+    mp_accumG = NULL;
+    mp_accumP = NULL;
+    mp_accumQ = NULL;
 
     if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_DSA)
         return; // Nothing to do with us
@@ -220,7 +223,7 @@ OpenSSLCryptoKeyDSA::OpenSSLCryptoKeyDSA
     DSA_get0_pqg(EVP_PKEY_get0_DSA(k), &otherP, &otherQ, &otherG);
 
     if (otherP != NULL && otherQ != NULL && otherG != NULL) {
-        DSA_set0_pqg(EVP_PKEY_get0_DSA(k), BN_dup(otherP), BN_dup(otherQ), BN_dup(otherG));
+        DSA_set0_pqg(mp_dsaKey, BN_dup(otherP), BN_dup(otherQ), BN_dup(otherG));
     }
 
     const BIGNUM *otherPriv = NULL, *otherPub = NULL;
@@ -233,7 +236,7 @@ OpenSSLCryptoKeyDSA::OpenSSLCryptoKeyDSA
         if (otherPriv != NULL)
             newPriv = BN_dup(otherPriv);
 
-        DSA_set0_key(EVP_PKEY_get0_DSA(k), BN_dup(otherPub), newPriv);
+        DSA_set0_key(mp_dsaKey, BN_dup(otherPub), newPriv);
 
     }
 }
@@ -315,8 +318,7 @@ bool OpenSSLCryptoKeyDSA::verifyBase64Si
 
     DSA_SIG * dsa_sig = DSA_SIG_new();
 
-    dsa_sig->r = BN_dup(R);
-    dsa_sig->s = BN_dup(S);
+    DSA_SIG_set0(dsa_sig, BN_dup(R), BN_dup(S));
 
     BN_free(R);
     BN_free(S);
@@ -367,11 +369,16 @@ unsigned int OpenSSLCryptoKeyDSA::signBa
     }
 
     // Now turn the signature into a base64 string
+    
+    const BIGNUM *dsaSigR;
+    const BIGNUM *dsaSigS;
+
+    DSA_SIG_get0(dsa_sig, &dsaSigR, &dsaSigS);
 
-    unsigned char* rawSigBuf = new unsigned char[(BN_num_bits(dsa_sig->r) + BN_num_bits(dsa_sig->s) + 7) / 8];
+    unsigned char* rawSigBuf = new unsigned char[(BN_num_bits(dsaSigR) + BN_num_bits(dsaSigS) + 7) / 8];
     ArrayJanitor<unsigned char> j_sigbuf(rawSigBuf);
     
-    unsigned int rawLen = BN_bn2bin(dsa_sig->r, rawSigBuf);
+    unsigned int rawLen = BN_bn2bin(dsaSigR, rawSigBuf);
 
     if (rawLen <= 0) {
 
@@ -380,7 +387,7 @@ unsigned int OpenSSLCryptoKeyDSA::signBa
 
     }
 
-    unsigned int rawLenS = BN_bn2bin(dsa_sig->s, (unsigned char *) &rawSigBuf[rawLen]);
+    unsigned int rawLenS = BN_bn2bin(dsaSigS, (unsigned char *) &rawSigBuf[rawLen]);
 
     if (rawLenS <= 0) {
 

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.cpp Fri Dec 16 22:42:56 2016
@@ -33,6 +33,8 @@
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoBase64.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoProvider.hpp>
+#include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
+
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/enc/XSECCryptoUtils.hpp>
 #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
@@ -128,10 +130,10 @@ OpenSSLCryptoKeyEC::OpenSSLCryptoKeyEC(E
 
     // Create a new key to be loaded as we go
 
-    if (k == NULL || k->type != EVP_PKEY_EC)
+    if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_EC)
         return; // Nothing to do with us
 
-    mp_ecKey = EC_KEY_dup(k->pkey.ec);
+    mp_ecKey = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(k));
 }
 
 // --------------------------------------------------------------------------------
@@ -188,15 +190,17 @@ bool OpenSSLCryptoKeyEC::verifyBase64Sig
 
     // Translate to BNs by splitting in half, and thence to ECDSA_SIG
 
-    ECDSA_SIG * dsa_sig = ECDSA_SIG_new();
-    dsa_sig->r = BN_bin2bn(sigVal, sigValLen / 2, NULL);
-    dsa_sig->s = BN_bin2bn(&sigVal[sigValLen / 2], sigValLen / 2, NULL);
+    ECDSA_SIG * ecdsa_sig = ECDSA_SIG_new();
+    BIGNUM *newR = BN_bin2bn(sigVal, sigValLen / 2, NULL);
+    BIGNUM *newS =  BN_bin2bn(&sigVal[sigValLen / 2], sigValLen / 2, NULL);
+
+    ECDSA_SIG_set0(ecdsa_sig, newR, newS);
 
     // Now we have a signature and a key - lets check
 
-    int err = ECDSA_do_verify(hashBuf, hashLen, dsa_sig, mp_ecKey);
+    int err = ECDSA_do_verify(hashBuf, hashLen, ecdsa_sig, mp_ecKey);
 
-    ECDSA_SIG_free(dsa_sig);
+    ECDSA_SIG_free(ecdsa_sig);
 
     if (err < 0) {
 
@@ -225,11 +229,11 @@ unsigned int OpenSSLCryptoKeyEC::signBas
             "OpenSSL:EC - Attempt to sign data with empty key");
     }
 
-    ECDSA_SIG * dsa_sig;
+    ECDSA_SIG * ecdsa_sig;
 
-    dsa_sig = ECDSA_do_sign(hashBuf, hashLen, mp_ecKey);
+    ecdsa_sig = ECDSA_do_sign(hashBuf, hashLen, mp_ecKey);
 
-    if (dsa_sig == NULL) {
+    if (ecdsa_sig == NULL) {
         throw XSECCryptoException(XSECCryptoException::ECError,
             "OpenSSL:EC - Error signing data");
     }
@@ -263,14 +267,18 @@ unsigned int OpenSSLCryptoKeyEC::signBas
     memset(rawSigBuf, 0, keyLen * 2);
     ArrayJanitor<unsigned char> j_sigbuf(rawSigBuf);
 
-    unsigned int rawLen = (BN_num_bits(dsa_sig->r) + 7) / 8;
-    if (BN_bn2bin(dsa_sig->r, rawSigBuf + keyLen - rawLen) <= 0) {
+    const BIGNUM *sigR;
+    const BIGNUM *sigS;
+    ECDSA_SIG_get0(ecdsa_sig, &sigR, &sigS);
+
+    unsigned int rawLen = (BN_num_bits(sigR) + 7) / 8;
+    if (BN_bn2bin(sigR, rawSigBuf + keyLen - rawLen) <= 0) {
         throw XSECCryptoException(XSECCryptoException::ECError,
             "OpenSSL:EC - Error copying signature 'r' value to buffer");
     }
 
-    rawLen = (BN_num_bits(dsa_sig->s) + 7) / 8;
-    if (BN_bn2bin(dsa_sig->s, rawSigBuf + keyLen + keyLen - rawLen) <= 0) {
+    rawLen = (BN_num_bits(sigS) + 7) / 8;
+    if (BN_bn2bin(sigS, rawSigBuf + keyLen + keyLen - rawLen) <= 0) {
         throw XSECCryptoException(XSECCryptoException::ECError,
             "OpenSSL:EC - Error copying signature 's' value to buffer");
     }

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp Fri Dec 16 22:42:56 2016
@@ -36,6 +36,7 @@
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/enc/XSECCryptoUtils.hpp>
 #include <xsec/framework/XSECError.hpp>
+#include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
 
 #include <openssl/err.h>
 #include <openssl/rand.h>
@@ -369,33 +370,34 @@ OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA
 
     mp_rsaKey = RSA_new();
 
-    if (k == NULL || k->type != EVP_PKEY_RSA)
+    if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_RSA)
         return; // Nothing to do with us
 
-    if (k->pkey.rsa->n)
-        mp_rsaKey->n = BN_dup(k->pkey.rsa->n);
+    RSA *rsa = EVP_PKEY_get0_RSA(k);
 
-    if (k->pkey.rsa->e)
-        mp_rsaKey->e = BN_dup(k->pkey.rsa->e);
+    if (rsa->n)
+        mp_rsaKey->n = BN_dup(rsa->n);
 
-    if (k->pkey.rsa->d)
-        mp_rsaKey->d = BN_dup(k->pkey.rsa->d);
+    if (rsa->e)
+        mp_rsaKey->e = BN_dup(rsa->e);
 
-    if (k->pkey.rsa->p)
-        mp_rsaKey->p = BN_dup(k->pkey.rsa->p);
+    if (rsa->d)
+        mp_rsaKey->d = BN_dup(rsa->d);
 
-    if (k->pkey.rsa->q)
-        mp_rsaKey->q = BN_dup(k->pkey.rsa->q);
+    if (rsa->p)
+        mp_rsaKey->p = BN_dup(rsa->p);
 
-    if (k->pkey.rsa->dmp1)
-        mp_rsaKey->dmp1 = BN_dup(k->pkey.rsa->dmp1);
+    if (rsa->q)
+        mp_rsaKey->q = BN_dup(rsa->q);
 
-    if (k->pkey.rsa->dmq1)
-        mp_rsaKey->dmq1 = BN_dup(k->pkey.rsa->dmq1);
+    if (rsa->dmp1)
+        mp_rsaKey->dmp1 = BN_dup(rsa->dmp1);
 
-    if (k->pkey.rsa->iqmp)
-        mp_rsaKey->iqmp = BN_dup(k->pkey.rsa->iqmp);
+    if (rsa->dmq1)
+        mp_rsaKey->dmq1 = BN_dup(rsa->dmq1);
 
+    if (rsa->iqmp)
+        mp_rsaKey->iqmp = BN_dup(rsa->iqmp);
 }
 
 // --------------------------------------------------------------------------------

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoProvider.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoProvider.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoProvider.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoProvider.cpp Fri Dec 16 22:42:56 2016
@@ -43,6 +43,7 @@
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoSymmetricKey.hpp>
+#include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
 
 #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
 
@@ -343,7 +344,7 @@ XSECCryptoKey* OpenSSLCryptoProvider::ke
     if (pkey) {
         XSECCryptoKey* ret = NULL;
         try {
-            switch (pkey->type) {
+            switch (EVP_PKEY_id(pkey)) {
                 case EVP_PKEY_RSA:
                     ret = new OpenSSLCryptoKeyRSA(pkey);
                     break;

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLCryptoX509.cpp Fri Dec 16 22:42:56 2016
@@ -37,6 +37,7 @@
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
+#include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
 
@@ -191,7 +192,7 @@ XSECCryptoKey::KeyType OpenSSLCryptoX509
 
     XSECCryptoKey::KeyType ret;
 
-    switch (pkey->type) {
+    switch (EVP_PKEY_id(pkey)) {
 
     case EVP_PKEY_DSA :
 
@@ -241,7 +242,7 @@ XSECCryptoKey * OpenSSLCryptoX509::clone
             "OpenSSL:X509 - cannot retrieve public key from cert");
     }
 
-    switch (pkey->type) {
+    switch (EVP_PKEY_id(pkey)) {
 
     case EVP_PKEY_DSA :
 

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.cpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.cpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.cpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.cpp Fri Dec 16 22:42:56 2016
@@ -114,6 +114,25 @@ int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGN
     return 1;
 }
 
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+    if (pr != NULL)
+        *pr = sig->r;
+    if (ps != NULL)
+        *ps = sig->s;
+}
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+    if (r == NULL || s == NULL)
+        return 0;
+    BN_clear_free(sig->r);
+    BN_clear_free(sig->s);
+    sig->r = r;
+    sig->s = s;
+    return 1;
+}
+
 DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
 {
     if (pkey->type != EVP_PKEY_DSA) {
@@ -122,6 +141,31 @@ DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
     return pkey->pkey.dsa;
 }
 
+#if defined (XSEC_OPENSSL_HAVE_EC)
+
+#include <openssl/ecdsa.h>
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+    if (pr != NULL)
+        *pr = sig->r;
+    if (ps != NULL)
+        *ps = sig->s;
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+    if (r == NULL || s == NULL)
+        return 0;
+    BN_clear_free(sig->r);
+    BN_clear_free(sig->s);
+    sig->r = r;
+    sig->s = s;
+    return 1;
+}
+
+#endif
+
 #endif
 
 #endif
\ No newline at end of file

Modified: santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.hpp
URL: http://svn.apache.org/viewvc/santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.hpp?rev=1774677&r1=1774676&r2=1774677&view=diff
==============================================================================
--- santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.hpp (original)
+++ santuario/xml-security-cpp/trunk/xsec/enc/OpenSSL/OpenSSLSupport.hpp Fri Dec 16 22:42:56 2016
@@ -20,6 +20,9 @@
 #if defined (XSEC_HAVE_OPENSSL)
 #include <openssl/evp.h>
 #include <openssl/dsa.h>
+#if defined (XSEC_OPENSSL_HAVE_EC)
+#include <openssl/ecdsa.h>
+#endif
 
 // Our own helper functions
 const BIGNUM *DSA_get0_pubkey(const DSA *dsa);
@@ -33,10 +36,24 @@ int DSA_set0_key(DSA *d, BIGNUM *pub_key
 void DSA_get0_pqg(const DSA *d,
                   const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
 int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+
+#if defined (XSEC_OPENSSL_HAVE_EC)
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+
+#endif
 
 DSA *EVP_PKEY_get0_DSA(EVP_PKEY *pkey);
 
+#define EVP_PKEY_id(_evp_) ((_evp_)->type)
+#define EVP_PKEY_get0_EC_KEY(_evp_) ((_evp_)->pkey.ec)
+#define EVP_PKEY_get0_RSA(_evp_) ((_evp_)->pkey.rsa)
+
 #endif
 
 
-#endif
\ No newline at end of file
+#endif