3

As an exercise in integrating my own code, by means of an external API, with a programming interface for some system, I encounter the following problem: Apple has marked most of the OpenSSL API as "deprecated". Any helpt will be greatly appreciated!

I have grabbed the OpenSSL 1.0.1i 6 Aug 2014 version from http://www.openssl.org/.

Attempting to link statically to the "sick horse" was futile:

g++ test.cc -o test -lssl -Bstatic -L/usr/local/ssl/include -lcrypto -lcurcl

I want to add that I was instructed to compile C++ code using the G++ compiler as follows.

g++ test.cc -o test -lssl -lcrypto -lcurl

Both calls exit with the following.

Output Example:

test.cc: In function ‘std::string encode_base64(const std::string&)’:
test.cc:104: warning: ‘BIO_new’ is deprecated (declared at /usr/include/openssl/bio.h:581)
test.cc:104: warning: ‘BIO_f_base64’ is deprecated (declared at /usr/include/openssl/evp.h:647)
test.cc:104: warning: ‘BIO_f_base64’ is deprecated (declared at /usr/include/openssl/evp.h:647)
test.cc:104: warning: ‘BIO_new’ is deprecated (declared at /usr/include/openssl/bio.h:581)
test.cc:105: warning: ‘BIO_new’ is deprecated (declared at /usr/include/openssl/bio.h:581)
test.cc:105: warning: ‘BIO_s_mem’ is deprecated (declared at /usr/include/openssl/bio.h:616)
test.cc:105: warning: ‘BIO_s_mem’ is deprecated (declared at /usr/include/openssl/bio.h:616)
test.cc:105: warning: ‘BIO_new’ is deprecated (declared at /usr/include/openssl/bio.h:581)
test.cc:106: warning: ‘BIO_push’ is deprecated (declared at /usr/include/openssl/bio.h:594)
test.cc:106: warning: ‘BIO_push’ is deprecated (declared at /usr/include/openssl/bio.h:594)
test.cc:107: warning: ‘BIO_write’ is deprecated (declared at /usr/include/openssl/bio.h:587)
test.cc:107: warning: ‘BIO_write’ is deprecated (declared at /usr/include/openssl/bio.h:587)
test.cc:108: warning: ‘BIO_ctrl’ is deprecated (declared at /usr/include/openssl/bio.h:590)
test.cc:108: warning: ‘BIO_ctrl’ is deprecated (declared at /usr/include/openssl/bio.h:590)
test.cc:109: warning: ‘BIO_ctrl’ is deprecated (declared at /usr/include/openssl/bio.h:590)
test.cc:109: warning: ‘BIO_ctrl’ is deprecated (declared at /usr/include/openssl/bio.h:590)
test.cc:113: warning: ‘BIO_free_all’ is deprecated (declared at /usr/include/openssl/bio.h:596)
test.cc:113: warning: ‘BIO_free_all’ is deprecated (declared at /usr/include/openssl/bio.h:596)
test.cc: In function ‘std::string encrypt(const std::string&)’:
test.cc:122: warning: ‘OPENSSL_add_all_algorithms_noconf’ is deprecated (declared at /usr/include/openssl/evp.h:828)
test.cc:122: warning: ‘OPENSSL_add_all_algorithms_noconf’ is deprecated (declared at /usr/include/openssl/evp.h:828)
test.cc:136: warning: ‘RSA_public_encrypt’ is deprecated (declared at /usr/include/openssl/rsa.h:275)
test.cc:140: warning: ‘RSA_public_encrypt’ is deprecated (declared at /usr/include/openssl/rsa.h:275)
test.cc:144: warning: ‘RSA_free’ is deprecated (declared at /usr/include/openssl/rsa.h:282)
test.cc:144: warning: ‘RSA_free’ is deprecated (declared at /usr/include/openssl/rsa.h:282)

Source Code Example (test.cc):

#include <string>
#include <iostream>
#include <sstream>
#include <ctime>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/x509v3.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <curl/curl.h>

using namespace std;

string create_blob(const string &username, const string &password);
string encode_base64(const string &s);
string url_encode(CURL *curl, const string &s);
string encrypt(const string &s);
string timestamp_in_ms();
void login(const string &username, const string &password);

template <typename T>
string to_string(const T &v) 
{ 
  stringstream ss;
  ss << v;
  return ss.str();
};

int main(int argc, const char* argv[])
{
  if (argc != 3) {
    cerr << "Usage: " << argv[0] << "<username> <password>";
    exit(1);
  }
  string username = string(argv[1]);
  string password = string(argv[2]);
  login(username, password);
};

void login(const string &username, const string &password) 
{
  CURL *curl;
  CURLcode res;

  curl_global_init(CURL_GLOBAL_ALL);

  curl = curl_easy_init();
  if (!curl) {
    cerr << "Error starting curl" << endl;
    exit(1);
  }

  struct curl_slist *header = NULL;
  header = curl_slist_append(header, "Accept-Language: sv");
  header = curl_slist_append(header, "Accept: application/json");

  string blob = create_blob(username, password);
  string postdata = "auth=" + url_encode(curl, blob) + "&service=NEXTAPI";

  curl_easy_setopt(curl, CURLOPT_URL, 
    "https://api.test.nordnet.se/next/1/login");
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata.c_str());
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postdata.length());
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);

  res = curl_easy_perform(curl);

  curl_slist_free_all(header);
  curl_easy_cleanup(curl);

}

string create_blob(const string &username, const string &password) 
{
  string encoded =
    encode_base64(username) + ":" +
    encode_base64(password) + ":" +
    encode_base64(timestamp_in_ms());
  return encode_base64(encrypt(encoded));
}

string timestamp_in_ms() 
{
  return to_string(std::time(0)) + "000";
}

string url_encode(CURL *curl, const string &s)
{
  char *url_encoded = curl_easy_escape(curl, s.c_str(), s.length());
  string url_encoded_str(url_encoded);
  curl_free(url_encoded);

  return url_encoded_str;
}

string encode_base64(const string &s) {
  BIO *bmem, *b64;
  BUF_MEM *bptr;

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, s.c_str(), s.length());
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

  string base64 = string(bptr->data,bptr->length-1);

  BIO_free_all(b64);

  return base64;
}

string encrypt(const string &s) {
  RSA *public_key;  
  FILE *fp;

  OpenSSL_add_all_algorithms();

  fp = fopen("NEXTAPI_TEST_public.pem","r");
  public_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
  fclose(fp);

  if (!public_key) {
    cerr << "Can't read public key" << endl;
    exit(1);
  }

  unsigned char encrypted[2560] = {0};

  int len = 
    RSA_public_encrypt(s.length(), 
               reinterpret_cast<unsigned char*>(const_cast<char *>(s.c_str())), 
               encrypted, 
               public_key, 
               RSA_PKCS1_PADDING);

  string result(reinterpret_cast<const char *>(encrypted), len);

  RSA_free(public_key);

  return result;
}

Similar Questions:

OpenSSL with gcc on OS X 10.7

'SHA1' is deprecated: first deprecated in OS X 10.7?

http://www.unix.com/programming/162567-linking-openssl-libcrypto-statically.html

Community
  • 1
  • 1
day1pnl
  • 99
  • 1
  • 5
  • Pay attention to Petesh's comments. Apple ignores `-Bstatic`, so you will always link against the shared object if available. That will cause obscure errors from loading Apple's 0.9.8 at runtime even though you're certain you linked against your 1.0.1 version. (0.9.8 and 1.0.1 are *not* binary compatible, and it causes a bunch of odd errors). – jww Aug 12 '14 at 17:38
  • This should be `-I`, not `-L`: `-L/usr/local/ssl/include`. But you would use `-L/usr/local/ssl/lib`. Petesh answer is more complete, and you should follow his advice. – jww Aug 13 '14 at 03:44
  • And here's the kicker: you may need to download and build cURL against 1.0.1 too. I'm not sure its a good idea to use Apple's version which was compiled/linked against OpenSSL 0.9.8. – jww Aug 13 '14 at 03:47

1 Answers1

2

The warnings indicate that you're still compiling against the apple supplied openssl library, as the .h files from this library are the ones that are decorated with the deprecation warnings.

You need to compile your code looking for the openssl includes in /usr/local/ssl/include (on the assumption that that is where you installed your copy of the library:

-I/usr/local/ssl/include

Secondly, it looks like OSX doesn't do anything with the -static option - no matter what you try it will link to the dynamic version, so you need to explicitly reference the libcrypto.a file in full in the path:

/usr/local/ssl/lib/libcrypto.a

so your compilation line becomes:

g++ -I/usr/local/ssl/include test.cc -o test /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -lcurl

(I presume it's -lcurl, I've never seen libcurcl before).

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • *"Secondly, it looks like OSX doesn't do anything with the -static option - no matter what you try it will link to the dynamic version"* - correct. And they even do it for iOS, where its not allowed!!! In this case, another option is to delete the shared object so it cannot be linked against. Its not a loss since it can't be used in practice anyways on iOS. – jww Aug 12 '14 at 17:36
  • Other gotcha'a on Apple are `rpath` and `LD_PRELOAD`. Both are silently ignored, too. He will need to use `DYLD_LIBRARY_PATH` instead if he's tweaking the runtime link/loader. See [`dyld(1)`](http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html) man pages. – jww Aug 12 '14 at 17:42
  • Thank you. I'll go ahead and set this as my accepted answer. – day1pnl Aug 13 '14 at 07:11