OpenSSL ライブラリを利用したプログラム開発の問題解決

こんなエラーが出る.

1>------ ビルド開始: プロジェクト: keyPairOut, 構成: Debug Win32 ------
1>コンパイルしています...
1>main.cpp
1>c:\software\develop\openssl\include\openssl\x509.h(207) : error C2143: 構文エラー : ')' が '定数' の前にありません。
1>c:\software\develop\openssl\include\openssl\x509.h(207) : error C2143: 構文エラー : ';' が '定数' の前にありません。
1>c:\software\develop\openssl\include\openssl\x509.h(207) : error C2040: 'LPCSTR' : 'STACK' は 'const CHAR *' と間接操作のレベルが異なります。
1>c:\software\develop\openssl\include\openssl\x509.h(207) : error C2059: 構文エラー : ')'
1>c:\software\develop\openssl\include\openssl\x509.h(929) : error C2226: 構文エラー : 'LPCSTR' 型指定子の前あるいは内部で構文エラーが発生しました。
1>c:\software\develop\openssl\include\openssl\x509.h(929) : error C2065: 'a' : 定義されていない識別子です。
1>c:\software\develop\openssl\include\openssl\x509.h(929) : error C2062: 型 'unsigned char' は不要です。
1>c:\software\develop\openssl\include\openssl\x509.h(929) : error C2226: 構文エラー : 'LPCSTR' 型指定子の前あるいは内部で構文エラーが発生しました。
1>ビルドログは "file://c:\Documents and Settings\hoge\My Documents\Visual Studio 2008\Projects\keyPairOut\Debug\BuildLog.htm" に保存されました。
1>keyPairOut - エラー 8、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

環境は,

WinCrypt.h のインクルードガード,__WINCRYPT_H__ を定義したらコンパイルが通った.

ひらめき

  1. いろいろやっている中,「wincrypt x509.h X509_NAME」で Google 検索した
  2. http://sourcejam.com/jp/openssl-0.9.8b/include_2openssl_2x509_8h-source.html に到達した
  3. 第107行以下数行を見て衝撃が走った
  4. Windows SDK の WinCrypt.h を確認し,X509_NAME の定義を発見した
  5. 試しに __WINCRYPT_H__ を定義してビルドし,通ることを確認した

私が書いていたコードは RSA 暗号のキーペアを生成・ファイル出力するもの.エントリ後部で全文を掲載している.

その他

この問題は OpenSSL 使用トラブル - BiBoLoG の件と同一で,その時から5週間経過している.

別件で numeric_limits::max(),numeric_limits::min() についてトラブルがあった.部分インクルードガード NOMINMAX により WinDef.h の同名マクロを除外できた.このトラブル回避法は inlineとdefineの違い -関数をinlineとして使うとdefineより優れている- C言語・C++・C# | 教えて!goo の情報が助けとなった.

今までこの問題が放置されていたのは 1.0.0 Beta 3 を独自ビルドしたものを利用していたため.別件で MSVC が致命的なエラーを云々が発生した.いろいろ検索し,http://osdir.com/ml/encryption.openssl.user/2002-05/msg00105.html から

に関連するらしいと理解した.この問題を回避するためにビルド済みライブラリを利用すればいいじゃーんと思い立ち,今回,5週前のトラブルと再会した.MD 版を自分でビルドできればいいんだろうが,方法が分からないしなあ.5週前のトラブルを今日1日で解決できたのはうれしい.

main.cpp

#include <stdio.h>
#include <string.h>
#define __WINCRYPT_H__
#include <openssl/rsa.h>
#include <openssl/engine.h>
#include <openssl/pem.h>

#pragma comment(lib, "libeay32md.lib")
#pragma comment(lib, "libssl32md.lib")

// http://www.fireproject.jp/feature/c-language/openssl/rsa.html
// キーペアの作成
static void printError(char *msg, unsigned long err);

int
main(int argc, char *argv[])
{
	int size = 2048;
	unsigned long exponent = 65537;
	FILE *privateKeyFile;
	FILE *publicKeyFile;

	if(argc != 3)
	{
		fprintf(stderr,
			"Usage : %s privateKeyFile publicKeyFile\n", argv[0]);
		exit(-1);
	}
	else
	{
		fopen_s(&privateKeyFile, argv[1], "w");
		if (privateKeyFile == NULL)
		{
			perror("failed to fopen");
			exit(-1);
		}

		fopen_s(&publicKeyFile, argv[2], "w");
		if (publicKeyFile == NULL)
		{
			perror("failed to fopen");
			exit(-1);
		}
	}

	// キーペアの作成
	RSA *rsaKey = RSA_generate_key(size, exponent, NULL, NULL);
	if (rsaKey == NULL)
	{
		printError("failed to RSA_generate_key",
			ERR_get_error());
		exit(-1);
	}

	if(RSA_print_fp(stdout, rsaKey, 0) != 1)
	{
		printError("failed to RSA_print_fp",
			ERR_get_error());
		exit(-1);
	}

	// 公開鍵をPEM形式で書き出し
	if(PEM_write_RSAPublicKey(publicKeyFile, rsaKey) != 1)
	{
		printError("failed to PEM_write_RSAPublicKey",
			ERR_get_error());
		exit(-1);
	}

	// 秘密鍵をPEM形式で書き出し
	if(PEM_write_RSAPrivateKey(privateKeyFile, rsaKey,
		NULL,
		NULL, 0,
		NULL, NULL) != 1)
	{
		printError("failed to PEM_write_RSAPrivateKey",
			ERR_get_error());
		exit(-1);
	}

	// 領域の開放
	RSA_free(rsaKey);

	fclose(privateKeyFile);
	fclose(publicKeyFile);

	return 0;
}

static void
printError(char *msg, unsigned long err)
{
	char *errmsg = ERR_error_string(err, NULL);
	fprintf(stderr, "%s(%s)\n",
		msg,
		errmsg);
}