RSAのEncrypt/Decrypt で例外が出るときの対処

要約

RSACryptoServiceProvider を使って Encrypt を呼び出した場合、文字列が長いと WindowsCryptographicException が出る。(Decryptの場合は CryptographicException) その場合は KeySize と パディングから最大長を割り出してそのサイズ以下でブロック化し暗号化・復号化を行う必要がある。また、暗号化したブロックのサイズは復号化するときにわかるように情報を付与しておかないと復号化は難しそうだ。

基本的には非対称暗号で大きなデータを扱うのではなく、共通鍵暗号をデータの暗号化に使用し、共通鍵の暗号化にのみ非対称暗号を使用するのが良いようだ。

参考資料

RSACryptoServiceProvider.Encrypt メソッド (System.Security.Cryptography) | Microsoft Docs

【C#】文字列を指定した文字数で分割する拡張メソッド - コガネブログ

Convert.ToBase64String メソッド (System) | Microsoft Docs

PHPのmcrypt関数で使用する初期化ベクトル(IV)とは公開されて… - 人力検索はてな

コード(非対称暗号での暗号化)

MSTest を使用して暗号化・復号化のサンプルを作成した。 TestEncryptAndDecrypt3 が今回のキモの部分。今回はパディングを PKCS # 1 v 1.5 で行うため、rsa.KeySize bit / 8 bit - 11 バイト = 117 バイトがブロック最大長となる。今回は暗号化したデータブロックを復号化サイドで判断できるようにするため、BASE64エンコードし改行で区切ることでブロックを分割した。

using System;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace EncryptTest
{
    [TestClass]
    public class UnitTest1
    {
        private string publicKey, privateKey;

        [TestInitialize]
        public void TestInit()
        {
            using (var rsa = new RSACryptoServiceProvider())
            {
                publicKey = rsa.ToXmlString(false);
                privateKey = rsa.ToXmlString(true);
            }
        }

        [DataTestMethod]
        [DataRow("Hello World!!")]
        [DataRow("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
        public void TestEncryptAndDecrypt1(string rawString)
        {
            var rawBytes = Encoding.ASCII.GetBytes(rawString);

            byte[] encryptedBytes;
            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(publicKey);
                encryptedBytes = rsa.Encrypt(rawBytes, false);
            }

            string decryptedString;
            using (var rsa = new RSACryptoServiceProvider())
            {
                byte[] decryptedBytes;

                rsa.FromXmlString(privateKey);
                decryptedBytes = rsa.Decrypt(encryptedBytes, false);
                decryptedString = Encoding.ASCII.GetString(decryptedBytes);
            }

            Assert.AreEqual(rawString, decryptedString);
        }

        [TestMethod]
        public void TestEncryptAndDecrypt2()
        {
            // 128 - 11 バイト (117 バイト) を超えると rsa.Encrypt() で例外が発生する。
            var rawString =
                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

            var rawBytes = Encoding.ASCII.GetBytes(rawString);

            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(publicKey);
                try
                {
                    rsa.Encrypt(rawBytes, false);
                }
                catch (Exception e)
                {
                    Assert.AreEqual("WindowsCryptographicException", e.GetType().Name);
                    return;
                }
                Assert.Fail("This Test should be thrown exception.");
            }
        }

        [DataTestMethod]
        [DataRow("Hello World!!")]
        [DataRow("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
        [DataRow("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
        public void TestEncryptAndDecrypt3(string rawString)
        {
            string encryptedBase64String;
            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(publicKey);

                var count = (rsa.KeySize / 8) - 11;
                var splitStrings = new List<string>();
                var length = (int)Math.Ceiling((double)rawString.Length / count);
                for (int i = 0; i < length; i++)
                {
                    int start = count * i;
                    if (rawString.Length <= start)
                    {
                        break;
                    }
                    if (rawString.Length < start + count)
                    {
                        splitStrings.Add(rawString.Substring(start));
                    }
                    else
                    {
                        splitStrings.Add(rawString.Substring(start, count));
                    }
                }

                var sb = new StringBuilder();
                foreach (var line in splitStrings)
                {
                    var tempBytes = Encoding.ASCII.GetBytes(line);
                    var tempEncBytes = rsa.Encrypt(tempBytes, false);
                    sb.AppendLine(Convert.ToBase64String(tempEncBytes, 0, tempEncBytes.Length));
                }
                encryptedBase64String = sb.ToString();
            }

            var decryptedString = "";
            using (var rsa = new RSACryptoServiceProvider())
            {
                byte[] decryptedBytes;

                rsa.FromXmlString(privateKey);

                foreach(var line in encryptedBase64String.Split('\n'))
                {
                    if (string.IsNullOrEmpty(line))
                        continue;

                    var base64Bytes = Convert.FromBase64String(line);
                    decryptedBytes = rsa.Decrypt(base64Bytes, false);
                    decryptedString += Encoding.ASCII.GetString(decryptedBytes);
                }
            }

            Assert.AreEqual(rawString, decryptedString);
        }
    }
}

コード(共通鍵暗号での暗号化)

さっきの例ではデータの暗号化に非対称暗号(RSA)を用いた。ただ、データが大きくなるにつれパフォーマンスの問題が出てくるらしい、なので、データの暗号化は共通鍵暗号を用い、共通鍵の暗号に非対称暗号を用いることで安全性・パフォーマンスの両面からカバーする。という方法が今の主流らしい。簡単に手順を示すと以下のようになる。

  1. 共通鍵受け渡しフロー

    1. 片側(A)で公開鍵・秘密鍵を生成
    2. (A)は公開鍵をもう一方(B)に受け渡す
    3. (B)は公開鍵を用い共通鍵を暗号化
    4. (B)は暗号化された共通鍵を(A)に渡す
    5. (A)は暗号化された共通鍵を自身の秘密鍵で復号化し保持
  2. 暗号化データ受け渡しフロー

    1. (B)は共通鍵でデータを暗号化
    2. (B)は暗号化されたデータをもう一方に受け渡す
    3. (A)は共通鍵で暗号化されたデータを復号化する

上記では便宜上データの暗号化を(B)で行っているが、共通鍵の受け渡しが終われば、データの暗号化はどちらが行っても問題なく行える。

以下、上記を実装したコードサンプルとなる。コード中の共通鍵のIVを平文で受け渡ししているが、暗号化・復号化が一回限りでIVを受け渡してすぐに行われるのであれば平文でもさほど問題ないようだ。(PHPのmcrypt関数で使用する初期化ベクトル(IV)とは公開されて… - 人力検索はてな)

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace AESTest
{
    [TestClass]
    public class UnitTest1
    {
        [DataTestMethod]
        [DataRow("Hello World!!")]
        [DataRow("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
        [DataRow("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
        public void TestEncryptAndDecrypt1(string rawString)
        {
            var decryptor = new Decryptor();
            var encryptor = new Encryptor();

            TransferCommonKey(encryptor, decryptor);

            byte[] iv, encryptedText;
            (iv, encryptedText) = encryptor.Encrypt(rawString);

            string decString;
            decString = decryptor.Decrypt(iv, encryptedText);

            Assert.AreEqual(rawString, decString);
        }

        private void TransferCommonKey(Encryptor encryptor, Decryptor decryptor)
        {
            string publicKey = decryptor.GetPublicKey();

            byte[] encryptedCommonKey = encryptor.GenerateEncryptedCommonKey(publicKey);

            decryptor.TransferCommonKey(encryptedCommonKey);
        }
    }

    class Encryptor
    {
        byte[] commonKey;

        public byte[] GenerateEncryptedCommonKey(string publicKey)
        {
            var aes = Aes.Create();
            commonKey = aes.Key;
            using var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(publicKey);
            return rsa.Encrypt(aes.Key, false);
        }

        public (byte[], byte[]) Encrypt(string text)
        {
            byte[] encrypted;

            var aes = Aes.Create();
            using (var ms = new MemoryStream())
            using (var cryptStream = new CryptoStream(ms, aes.CreateEncryptor(commonKey, aes.IV), CryptoStreamMode.Write))
            {
                using (var sWriter = new StreamWriter(cryptStream))
                {
                    sWriter.Write(text);
                }
                encrypted = ms.ToArray();
            }

            return (aes.IV, encrypted);
        }
    }

    class Decryptor
    {
        string publicKey, privateKey;

        byte[] commonKey;

        public Decryptor()
        {
            using var rsa = new RSACryptoServiceProvider();
            publicKey = rsa.ToXmlString(false);
            privateKey = rsa.ToXmlString(true);
        }

        public string GetPublicKey()
        {
            return publicKey;
        }

        public void TransferCommonKey(byte[] encryptedCommonKey)
        {
            using var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(privateKey);
            commonKey = rsa.Decrypt(encryptedCommonKey, false);
        }

        public string Decrypt(byte[] iv, byte[] data)
        {
            var aes = Aes.Create();
            using var ms = new MemoryStream(data);
            using var cryptStream = new CryptoStream(ms, aes.CreateDecryptor(commonKey, iv), CryptoStreamMode.Read);
            using var sReader = new StreamReader(cryptStream);
            return sReader.ReadLine();
        }
    }
}

プライベート認証局によるCA署名証明書の作成

参考資料

CAの証明書を作成

openssl の 設定ファイル

[ca]
default_ca = ca_default

[ca_default]
dir           = .
certs         = $dir/certs
crl_dir       = $dir/crl
new_certs_dir = $dir/newcerts
database      = $dir/index.txt
certificate   = $dir/certs/cacert.crt
serial        = $dir/serial
crlnumber     = $dir/crlnumber
crl           = $dir/crl.pem
private_key   = $dir/private/caprivkey.key

x509_extensions  = usr_cert

name_opt = ca_default
cert_opt = ca_default

default_days     = 365
default_crl_days = 30
default_md       = default
preserve         = no

policy = policy_anything

[ policy_anything ]
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional
domainComponent        = optional

[req]
prompt = no
distinguished_name = dn

[dn]
CN = Root CA
O  = Root CA
OU = Root CA
L  = localization
ST = state
C  = JP

[usr_cert]
basicConstraints       = CA:true,pathlen:0
nsComment              = "OpenSSL Generated Certificate"
extendedKeyUsage       = serverAuth,clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName         = @alt_names

[alt_names]
URI=http://ca.example.com
DNS.1=example.com

CAのプライベートキー作成

openssl genrsa -out caprivkey.key 2048

CAの証明書署名要求作成

openssl req -new -config ca.cnf -out cacert.csr -key caprivkey.key

証明書作成の前準備

mkdir newcerts
touch index.txt
echo 00 > serial

CAの証明書を自己署名証明書を作成

openssl ca -config ca.cnf -batch -extensions usr_cert -out cacert.crt -in cacert.csr -selfsign -keyfile caprivkey.key

CA署名証明書の作成

openssl の設定ファイル

CAの時とほぼ同じだが、basicConstraints が違う。CAではないので、falseにする。

[ca]
default_ca = ca_default

[ca_default]
dir           = .
certs         = $dir/certs
crl_dir       = $dir/crl
new_certs_dir = $dir/newcerts
database      = $dir/index.txt
certificate   = $dir/certs/cacert.crt
serial        = $dir/serial
crlnumber     = $dir/crlnumber
crl           = $dir/crl.pem
private_key   = $dir/private/caprivkey.key

x509_extensions  = usr_cert

name_opt = ca_default
cert_opt = ca_default

default_days     = 365
default_crl_days = 30
default_md       = default
preserve         = no

policy = policy_anything

[ policy_anything ]
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional
domainComponent        = optional

[req]
prompt = no
distinguished_name = dn

[dn]
CN = My Certificate
ST = Japan
C  = JP

[usr_cert]
basicConstraints       = CA:false
nsComment              = "OpenSSL Generated Certificate"
extendedKeyUsage       = serverAuth,clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName         = @alt_names

[alt_names]
URI=http://cert.example.com
DNS.1=example.com

CA署名証明書を作成する前準備

mkdir private
mv caprivkey.key private/caprivkey.key
mkdir certs
mv cacert.crt certs/cacert.crt

CA署名対象の秘密鍵の作成

openssl genrsa -out server.key 2048

証明書署名要求作成

openssl req -new -config cert.cnf -out server.csr -key server.key

CA署名証明書の作成

openssl ca -config cert.cnf -batch -extensions usr_cert -out server.crt -in server.csr

おまけ

証明書を PEM から DER に変換

openssl x509 -in server.crt -inform pem -out server.der -outform der

CRLを発行(空)

echo 00 > crlnumber

openssl ca -gencrl -config ca.cnf -out crl.pem

CRLをPEMからDERに変換

openssl crl -in crl.pem -inform pem -out crl.crl -outform der

(C#) 並行処理キー入力まちプログラム

参考サイト

mslgt.hatenablog.com

ポイント

CancellationTokenSource() でトークン作成して、トークンからキャンセル用トークンを生成して、それをすべての非同期タスクで共有して、キャンセルが起きた時の処理をタスクに書くってとこ。

今回は WaitKeyTask でしかキャンセルしてないけど、すべてのタスクで共有して、WaitKeyTaskともども Task.WaitAll() で待っておけば、どこからでもキャンセルできるようになると思う。

コード

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace ExampleOfWaitKey
{
    class Program
    {
        static void Task1(CancellationToken token, string c, int duration)
        {
            while (true)
            {
                Console.Write(c);
                Task.Delay(duration).Wait();

                if(token.IsCancellationRequested)
                {
                    // WaitKeyTask() でキャンセルが発行されると
                    // Task.Delay().Wait() 明けにこちらに落ちる

                    // 終了に時間がかかるような処理の代わり
                    var t = new Random().Next(1,10);
                    Task.Delay(t * 100).Wait();

                    Console.WriteLine();
                    Console.WriteLine("{0}: was canceled", c);
                    return;
                }
            }
        }

        static void WaitKeyTask(CancellationTokenSource tokenSource)
        {
            Console.ReadLine(); // キー入力まち
            tokenSource.Cancel(); // キャンセル通知
        }

        static void Main(string[] args)
        {
            // キャンセル伝播用トークンの作成
            var tokenSource = new CancellationTokenSource();
            var cancelToken = tokenSource.Token;

            // キー入力待ち非同期タスクの実行
            var waitKeyTask = Task.Run(() =>WaitKeyTask(tokenSource));

            // 非同期処理タスクの実行
            // 
            var tasks = new List<Task>();
            tasks.Add(Task.Run(() => Task1(cancelToken, "a", 100)));
            tasks.Add(Task.Run(() => Task1(cancelToken, "b", 200)));

            // キー入力待ち
            waitKeyTask.Wait();

            Console.WriteLine();
            Console.WriteLine("キーが押されました。");
            Console.WriteLine("すべてのタスクが終了するのを待ちます...");

            // 全タスクのキャンセル処理待ち
            Task.WaitAll(tasks.ToArray());
        }
    }
}

Vue.js 練習

これはなに?

私が Vue.js を練習した時の忘備録的記録です。詳しい内容が知りたいならオフィシャルのリファレンスを見たほうがよいです。日本語ですし。

経緯

最近 PHP でもやってみるかな、と思って始めたけど、テンプレートエンジンでいいのがなさそうだったので(というか、Smarty しかつかってないけど)、それなら Vue.js をフロントにしてみては? と思って使い始めてる。気に入らなかったらやめると思う。

ちなみにVue.js をPHPのフロントにする方法は以下のサイトに載ってます。

レガシー管理ページをちょっと動的にするためだけのVue.jsとPHP - Qiita

初めの一歩。Hello World

以下の html を サーバーに置くと Hello Vue!! と表示される。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{ message }}
    </div>

    <script type="text/javascript">
      var v = new Vue({
        el: "#app",
        data: {
            message: "Hello Vue!!"
        }
      });
    </script>
  </body>
</html>

<div id="app"> 下の要素で {{ }} でくくった部分を置き換える。というのが基本的な動作のようだ。

属性の動的生成

属性にデータを割り当てたいからと言って <a href="{{ link }}">test</a> という書き方はできないらしい。その代わりに <a v-bind:href="link">test</a> という書き方をする。 v-bind: というプレフィックスを属性名につけることで値にデータ名が使えるようになる。下記の例では link の部分が #app に置き換わる。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <a v-bind:href="link">test</a>
    </div>

    <script type="text/javascript">
      var v1 = new Vue({
        el: "#app",
        data: {
            link: "#app",
        }
      });
    </script>
  </body>
</html>

属性に式を指定して動的生成

さっきの例では バインドしている値はデータ名のみだが、値は式でもよい。以下の例では href="/sub_dir/" となる。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <a v-bind:href="link + '/'">test</a>
    </div>

    <script type="text/javascript">
      var v1 = new Vue({
        el: "#app",
        data: {
            link: "/sub_dir",
        }
      });
    </script>
  </body>
</html>

属性にメソッドを指定して動的生成

式だけではなくてメソッドも可能。オリジナルのメソッドだけではなく、組み込み関数も指定できる。例えば、<a v-bind:href="Math.abs(-100)">test</a> とすると <a href="100">test</a> が生成される。意味はない。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <a v-bind:href="goto('/')">test</a>
    </div>

    <script type="text/javascript">
      var v1 = new Vue({
        el: "#app",
        methods: {
            goto: function(path) {
                return "/sub_dir" + path;
            }
        }
      });
    </script>
  </body>
</html>

コンポーネント

でもやっぱり、属性に式とか関数とか書きたくない。一回だけならまだいいけど、何回も書くとなるともうちょっと違う感じで書きたい。

コンポーネントは独自のノードを作成するための手法。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <link_to uri="/"></link_to>
    </div>

    <script type="text/javascript">
      Vue.component('link_to', {
        props: ['uri'],
        template: `
          <a :href="uri">test</a>
        `
      })
      var v1 = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>

こんな感じでかける。ただ、これだど直接書くのと変わらないのでコンポーネント側で関数や式を使って入力値(ここでは uri ) を修飾してあげるとよいかも。ただ、オリジナルのメソッドやデータをコンポーネント内で使いたい場合には以下の例のように this.$root.goto(uri) のようにし、少し工夫する必要がある。何回も同じような記述をする場合はコンポーネントにまとめておくのがよさそうだ。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <link_to uri="/"></link_to>
    </div>

    <script type="text/javascript">
      Vue.component('link_to', {
        props: ['uri'],
        template: `
          <a :href="this.$root.goto(uri)">test</a>
        `
      })
      var v1 = new Vue({
        el: "#app",
        methods: {
            goto: function(uri) {
                return "/sub_dir" + uri;
            }
        }
      });
    </script>
  </body>
</html>

コンポーネントのネスト

先の例では、<a> 要素のテキストが test 固定になってしまって不便。props に足してもいいけど、HTMLっぽく書きたい場合もある。そういう場合は <slot> を使う。

<html>
  <head>
    <title></title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  </head>
  <body>

    <div id="app">
      <link_to uri="/">test</link_to>
    </div>

    <script type="text/javascript">
      Vue.component('link_to', {
        props: ['uri'],
        template: `
          <a :href="this.$root.goto(uri)"><slot></slot></a>
        `
      })
      var v1 = new Vue({
        el: "#app",
        methods: {
            goto: function(uri) {
                return "/sub_dir" + uri;
            }
        }
      });
    </script>
  </body>
</html>

おわり

おわり。

ディスクのパーティションを変更後、Linuxの起動が遅った問題

あらすじ

Virtual Box で初回 10GBで仮想ディスクを組んでしまい、途中で空き容量不足でLinuxが固まる問題が発生したので、仮想ディスク容量を拡張したが、パーティション設定が以前のままで、拡張部分が使えず結局空き容量不足という状態だった。KNOPPIXを入れて、gpartedにてパーティション設定を変更し、再度起動すると空き容量の問題は解決したが、起動時にジャーナルの再チェックが必ず入るようになり、1分30秒待たされることになった。

参考サイト

起動で1分半待たされる問題の解決法! | ウィンドウズにおさらばした文系中高年

原因

パーティション設定を変更したことで、スワップのUUIDが更新されてしまい、/etc/fstab のUUIDと違うことでLinuxが異常を検知してしまい、起動時にディスクチェックが走ってしまうのが問題のようです。

復旧方法

  • blkid コマンドでUUIDをチェック
$ sudo blkid
  • 表示されたUUIDを /etc/fstab に反映
$ sudo vim /etc/fstab
  • 起動時に「gave up waiting for suspend/resume device」が出る場合は /etc/initramfs-tools/conf.d/resumeも更新する
$ sudo vim /etc/initramfs-tools/conf.d/resume
$ sudo update-initramfs -u

以上!!

オレオレ証明書(自己著名証明書) DER ファイル作成 (サブジェクト代替名付き)

参考サイト

作成手順

秘密鍵を作成

$ openssl genrsa 2048 > server.key

証明書署名要求を作成

$ openssl req -new -key server.key > server.csr

自己署名証明書を作成

san.txt という名前でSubject Alternative Name(サブジェクト代替名)の設定を記載

subjectAltName = URI:hoge.com, DNS:fuga.com

-extfile オプションを使って SANを指定しつつ自己著名証明書を作成

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extfile san.txt

DERファイルの作成

$ openssl x509 -inform pem -outform der -in server.crt -out cacert.der

DERファイルの中身を見たい場合

$ openssl x509 -inform der -text < cacert.der

AWS EC2 nginx + php + postgresql

参考サイト

↑ phpinfo.php を作成した後、sudo systemctl restart nginx すること。

【詰まったこと】EC2側からRDS側にアクセスできなくて困った

RDS側のセキュリティグループのインバウンドルールにルールを追加するといけた。追加するのは、ソースにEC2側のセキュリティグループを足せばいい。

【プチ詰まり】psql の指定の方法がわからなかった

$ psql --host=DB_instance_endpoint --port=port --username=master_user_name --password --dbname=database_name

こんな感じでいけるっぽい。

【プチ詰まり】pdo_pgsql がない

上の記事にあるように yum でインストールしてあげる必要がある。

yum install -y  php-devel
yum install -y  php-gd
yum install -y  php-intl
yum install -y  php-json
yum install -y  php-mbstring
yum install -y  php-mcrypt
yum install -y  php-pdo
yum install -y  php-pgsql

【プチ詰まり】php の PDO でエラーが出る

Error :SQLSTATE[08006] [7] could not translate host name "***.rds.amazonaws.com" to address: Name or service not known

こんなエラーがでる。

→ 【解決】単純にURL間違ってた。。。

【プチ詰まり】composer のパス

/usr/local/bin/composer がパスなので、root だと実行パスにない状態となる。 root では /usr/local/bin/composer を指定すること。

【プチ詰まり】.env を導入したい

【小ネタ】

【プチ詰まり】sessionが機能しない

色々みてると、ファイルに権限がないことが原因だった。

Amazon Linux 2 の場合は /var/lib/php/session になってた。ただ、グループが apache になってたので、 nginx に変更したら動いた。