# 機能設計書 56-アセンブリ署名

## 概要

本ドキュメントは、F#コンパイラにおける.NETアセンブリの強い名前（Strong Name）署名機能について記述する。

### 本機能の処理概要

.NETアセンブリに対して強い名前署名を付与する機能を提供する。RSA暗号を使用してアセンブリのハッシュ値に署名し、アセンブリの一意性と改ざん検出を可能にする。

**業務上の目的・背景**：.NETアセンブリの強い名前署名は、アセンブリのバージョン管理と整合性検証に必要な機能である。GAC（Global Assembly Cache）への配置や、署名済みアセンブリからの参照には署名が必須となる。

**機能の利用シーン**：
- F#コンパイラでの署名付きDLL/EXE生成
- 遅延署名（DelaySign）ビルド
- 公開署名（PublicSign）ビルド
- キーコンテナを使用した署名

**主要な処理内容**：
1. 公開鍵/秘密鍵ペアの読み込み（.snkファイル）
2. アセンブリコンテンツのSHA1ハッシュ計算
3. RSA署名の生成
4. 署名のアセンブリへの埋め込み
5. 署名サイズの計算

**関連システム・外部連携**：
- System.Security.Cryptography（RSA暗号）
- System.Reflection.PortableExecutable（PEリーダー）

**権限による制御**：キーファイルへのアクセス権限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | プロジェクトプロパティ - 署名 | 設定画面 | 署名キーの設定 |

## 機能種別

セキュリティ / 暗号処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| keyBlob | byte[] | Yes | キーペアまたは公開鍵のバイト配列 | BLOB形式 |
| stream | Stream | Yes | 署名対象のPEストリーム | 有効なPE形式 |

### 入力データソース

- .snkファイル（キーペアファイル）
- 公開鍵ファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| publicKey | byte[] | CLR形式の公開鍵 |
| signatureSize | int | 署名サイズ（バイト） |
| - | 副作用 | ストリームへの署名書き込み |

### 出力先

- PEストリームのStrongNameSignatureディレクトリ

## 処理フロー

### 処理シーケンス

```
1. キーの読み込み
   └─ BlobReader でキーBLOBを解析
   └─ RSAParameters に変換

2. ハッシュ計算（hashAssembly）
   └─ PEヘッダーのハッシュ（チェックサム/セキュリティディレクトリを除く）
   └─ セクションのハッシュ（署名領域を除く）
   └─ SHA1で最終ハッシュ

3. 署名生成（createSignature）
   └─ RSA.Create()でRSAインスタンス生成
   └─ SignHash() でPKCS1パディング付き署名
   └─ バイト順序反転

4. 署名埋め込み（patchSignature）
   └─ StrongNameSignatureDirectory の位置特定
   └─ 署名バイト列の書き込み
   └─ CorFlagsに StrongNameSigned フラグ設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始: signStream] --> B[PEReaderでファイル読み込み]
    B --> C[hashAssemblyでハッシュ計算]
    C --> D[createSignatureで署名生成]
    D --> E[patchSignatureで署名埋め込み]
    E --> F[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-56-01 | SHA1ハッシュ | アセンブリハッシュはSHA1で計算 | 常時 |
| BR-56-02 | RSA署名 | 署名アルゴリズムはRSA with PKCS1パディング | 常時 |
| BR-56-03 | バイト反転 | 署名バイト列はリトルエンディアン（反転） | 常時 |
| BR-56-04 | キーコンテナ非対応 | クロスプラットフォームのためキーコンテナは非対応 | 常時 |

### 計算ロジック

**署名サイズ計算**:
- 公開鍵BLOBからRSAマジックナンバーを検証
- ビット長を読み取り、8で割って署名サイズ（バイト）を算出

## データベース操作仕様

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FSComp.SR.ilSignPrivateKeyExpected | 例外 | 秘密鍵が必要だが公開鍵のみ | キーペアファイルを使用 |
| FSComp.SR.ilSignRsaKeyExpected | 例外 | RSAキーでない | RSAキーを使用 |
| FSComp.SR.ilSignInvalidBitLen | 例外 | ビット長が16の倍数でない | 有効なキーを使用 |
| FSComp.SR.ilSignInvalidPKBlob | 例外 | 公開鍵BLOBが不正 | 有効な公開鍵を使用 |
| FSComp.SR.ilSignBadImageFormat | 例外 | PE形式が不正 | 有効なPEファイルを使用 |
| FSComp.SR.containerSigningUnsupportedOnThisPlatform | 例外 | キーコンテナ使用時 | ファイルベースの鍵を使用 |

### リトライ仕様

本機能にリトライ機構はない。

## トランザクション仕様

該当なし

## パフォーマンス要件

- インクリメンタルハッシュ（IncrementalHash）で効率的なハッシュ計算
- ストリーミング処理でメモリ使用量を抑制

## セキュリティ考慮事項

- 秘密鍵の安全な取り扱い（メモリ上での保持期間最小化）
- キーコンテナは非対応（セキュリティ上の理由ではなくクロスプラットフォーム対応のため）

## 備考

- キーコンテナ署名はこのプラットフォームでは非対応
- 公開署名（PublicSign）は署名領域をゼロ埋めして署名フラグのみ設定

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | KeyType型（16-18行目）でキー種別を理解 |
| 1-2 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | BlobReader構造体（125-143行目）でBLOB読み取りを理解 |
| 1-3 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | ByteArrayUnion（38-50行目）でバイト配列操作を理解 |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | ILStrongNameSigner型（343-394行目）が公開APIエントリーポイント |
| 2-2 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | signStream関数（292-301行目）が署名処理の中核 |

#### Step 3: ハッシュ計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | hashAssembly関数（56-123行目）でハッシュ計算ロジック |

**主要処理フロー**:
- **58-78行目**: PEヘッダーのハッシュ（チェックサム/セキュリティを除外）
- **90-120行目**: セクションのハッシュ（署名領域を除外）

#### Step 4: 署名生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | RSAParametersFromBlob関数（145-172行目）でキー変換 |
| 4-2 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | createSignature関数（262-269行目）で署名生成 |
| 4-3 | ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | patchSignature関数（271-290行目）で署名埋め込み |

### プログラム呼び出し階層図

```
ILStrongNameSigner.SignStream
    │
    └─ signerSignStreamWithKeyPair
           │
           └─ signStream
                  │
                  ├─ PEReader (System.Reflection.PortableExecutable)
                  │
                  ├─ hashAssembly
                  │      └─ IncrementalHash (SHA1)
                  │
                  ├─ createSignature
                  │      ├─ RSA.Create()
                  │      ├─ RSAParametersFromBlob
                  │      └─ RSA.SignHash (PKCS1)
                  │
                  └─ patchSignature
                         └─ Stream.Write (署名書き込み)
```

### データフロー図

```
[入力]                      [処理]                        [出力]

.snkファイル          ──▶  RSAParametersFromBlob     ──▶  RSAParameters
       │
       ▼
PEストリーム          ──▶  hashAssembly              ──▶  SHA1ハッシュ
       │
       ▼
RSA + ハッシュ        ──▶  createSignature           ──▶  署名バイト列
       │
       ▼
署名 + ストリーム     ──▶  patchSignature            ──▶  署名済みPE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ilsign.fs | `src/Compiler/AbstractIL/ilsign.fs` | ソース | 強い名前署名の実装 |
| ilwrite.fs | `src/Compiler/AbstractIL/ilwrite.fs` | ソース | ILライター（署名呼び出し元） |
