【テクニカル・上級編】【上級プロフェッショナル向け】「Digital Signature(デジタル署名)」の有無を確認し、未署名図面の外部送信を防止する保存制御 – AutoCAD VBA解析バイブル

スポンサーリンク
スポンサーリンク

「図面の完全性」を担保せよ:デジタル署名による出力制御の極致

エンジニアリングの現場において、図面は単なる「線の集合」ではない。それは契約の一部であり、法的責任を伴う「設計証跡」である。

大規模プロジェクト、あるいは防衛・航空宇宙といった高セキュリティ領域において、未署名(Unsigned)の図面が外部へ流出することは、プロトコルの崩壊を意味する。しかし、多くの現場では「人の注意」という、最も脆弱で不確実な要素にこの防壁を委ねている。

我々アーキテクトの使命は、この脆弱性を技術によって排除することだ。本稿では、AutoCAD VBAを用い、Windows APIとShellオブジェクトを高度に組み合わせることで、「デジタル署名が存在しない図面の、特定ディレクトリへの保存を物理的に阻止する」という、極めて堅牢なゲートキーパー・ロジックの実装手法を解説する。

1. 抽象化の罠:なぜ標準オブジェクトモデルでは不十分なのか

AutoCADのCOMインターフェース(`AcadDocument`など)は、図面の幾何学的な情報やレイヤー構造を操作するには極めて優秀だ。しかし、ファイルシステムレベルのメタデータ、特に「デジタル署名」の有無を判定するプロパティは、AutoCADのオブジェクトモデルには直接露出していない。

多くの凡庸なエンジニアは、ここで「外部ツールを呼び出す」といった、プロセス間通信のオーバーヘッドとエラーハンドリングの複雑化を招く設計を選択する。しかし、真のプロフェッショナルは、OSの深層にあるWindows Shell Interface、あるいはWinVerifyTrust APIに目を向ける。

今回は、実装の堅牢性と保守性のバランスを考慮し、Windows Shellの`PropertyStore`を利用して、拡張プロパティから署名状態を判定するアーキテクチャを採用する。

2. アーキテクチャ設計:Gatekeeper Pattern

単に「署名を確認する」だけでは不十分だ。実装すべきは、以下のワークフローを持つ「保存制御エンジン」である。

1. Target Identification: 保存先が「納品用(Delivery)」フォルダであるかを判定。
2. Metadata Extraction: Windows Shell APIを介して、DWGファイルのメタデータから署名ステータスを抽出。
3. Integrity Verification: 署名の有無に基づき、`SaveAs` 操作の可否を決定。
4. Resource Management: 使用したCOMオブジェクトを確実に解放し、AutoCADのメモリリークを防止。

3. 実装:極限の署名検証ロジック

以下に、実戦投入可能なコード構造を示す。ここでは、単なるコードの提示ではなく、「いかにしてメモリとエラーを制御するか」という観点を重視している。

Option Explicit

' --- Windows API / Shell Constants ---
Private Const CSIDL_FILES As Long = &H2
Private Const ShellPropertyDigitalSignature As Long = 253 ' 署名に関連するプロパティID(環境により変動の可能性あり)

''' <summary>
''' 図面のデジタル署名状態を検証し、納品用保存を制御するメインルーチン
''' </summary>
Public Sub SecureSaveWorkflow()
    Dim acadDoc As AcadDocument
    Set acadDoc = ThisDrawing
    
    Dim targetPath As String
    Dim deliveryFolder As String
    
    ' 納品用フォルダの定義(環境変数やレジストリから取得するのが理想)
    deliveryFolder = "C:\Project\Delivery\"
    
    ' 現在の保存先、または保存予定のパスを取得
    targetPath = acadDoc.FullName
    
    ' 1. 保存先が納品用フォルダかどうかの判定
    If InStr(1, targetPath, deliveryFolder, vbTextCompare) > 0 Then
        
        ' 2. デジタル署名の検証
        If Not IsDigitallySigned(targetPath) Then
            ' 署名がない場合、致命的なエラーとして処理を中断
            MsgBox "【致命的エラー】" & vbCrLf & _
                   "未署名の図面を納品用フォルダに保存することは、セキュリティプロトコル違反です。", _
                   vbCritical, "Integrity Violation"
            
            ' ここで処理を強制終了させる。SaveAsを実行させない。
            Exit Sub
        End If
        
        MsgBox "署名の整合性を確認しました。保存プロセスを続行します。", vbInformation
    End If

    ' 3. 保存実行(署名がある、または納品フォルダ以外の場合)
    On Error Resume Next
    acadDoc.Save
    If Err.Number <> 0 Then
        MsgBox "保存に失敗しました: " & Err.Description, vbExclamation
    End If
    On Error GoTo 0
End Function

''' <summary>
''' Windows Shellを使用して、ファイルのデジタル署名プロパティを解析する
''' </summary>
''' <param name="filePath">検証対象のファイルフルパス</param>
''' <returns>署名が存在する場合はTrue</returns>
Private Function IsDigitallySigned(ByVal filePath As String) As Boolean
    Dim shellApp As Object
    Dim folderObj As Object
    Dim fileObj As Object
    Dim varSignatureStatus As Variant
    Dim isSigned As Boolean
    
    isSigned = False ' デフォルトはFalse(Fail-Safe設計)

    ' オブジェクトの生成
    On Error GoTo ErrorHandler
    Set shellApp = CreateObject("Shell.Application")
    
    ' パスの分解(Shellオブジェクトはフォルダとファイルに分けて扱う必要がある)
    Dim parentFolder As String
    Dim fileName As String
    Dim pos As Integer
    pos = InStrRev(filePath, "\")
    parentFolder = Left(filePath, pos - 1)
    fileName = Mid(filePath, pos + 1)

    ' Shellオブジェクトへのアクセス
    Set folderObj = shellApp.Namespace(parentFolder)
    Set fileObj = folderObj.ParseName(fileName)

    ' Extended Propertyの取得
    ' 注意: プロパティIDはWindowsのバージョンやShellの仕様に依存する。
    ' 実務では、特定のプロパティIDをループで走査し、"Digital Signature"という名前を持つものを探す手法がより堅牢。
    
    ' ここでは簡略化のため、ShellのGetDetailsOfメソッドを利用して
    ' 署名に関する文字列情報の有無を確認するアプローチをとる。
    ' (実際の実装では、特定のIndex番号を特定するロジックを組み込む)
    
    Dim i As Integer
    For i = 0 To 300 ' Shellのプロパティインデックスを走査
        Dim detail As String
        detail = folderObj.GetDetailsOf(fileObj, i)
        
        ' 「署名」や「Signed」に関連するメタデータが検出されたかを確認
        ' ※実際の環境に合わせてキーワードは調整すること
        If InStr(1, detail, "署名", vbTextCompare) > 0 Or _
           InStr(1, detail, "Signature", vbTextCompare) > 0 Then
            
            ' 文字列が空でなければ、署名情報が存在するとみなす
            If Len(Trim(detail)) > 0 Then
                isSigned = True
                Exit For
            End If
        End If
    Next i

CleanUp:
    ' --- メモリ管理の極致 ---
    ' COMオブジェクトは明示的にNothingを代入し、参照カウンタを減らす。
    ' これを怠ると、AutoCADプロセスが「幽霊オブジェクト」を掴み続け、
    ' 大規模なバッチ処理時にメモリリークを引き起こす。
    Set fileObj = Nothing
    Set folderObj = Nothing
    Set shellApp = Nothing
    IsDigitallySigned = isSigned
    Exit Function

ErrorHandler:
    ' ログ出力等の処理をここに記述
    isSigned = False
    Resume CleanUp
End Function

4. 伝説的アーキテクトによる技術的洞察

メモリ管理とオブジェクトのライフサイクル

VBAにおける最大の敵は、`Set obj = Nothing` の欠如だ。特に `Shell.Application` のような外部COMオブジェクトを使用する場合、参照が残っているとAutoCADのバックグラウンドプロセスが終了せず、ゾンビプロセス化する。大規模な自動化システムを構築する場合、各関数内で確実に `CleanUp` ラベルへ到達させ、参照カウンタをゼロにする設計を徹底せよ。

Fail-Safe(フェイルセーフ)設計の原則

`IsDigitallySigned` 関数の初期値を `isSigned = False` としている点に注目してほしい。これは、エラーが発生した際や、予期せぬプロパティIDの変動があった際に、「署名がある」と誤判定するリスクを排除するためだ。セキュリティ実装において、「不明な場合は拒否する」という思想は絶対的な規律である。

性能への配慮

`For i = 0 To 300` というループは、一見非効率に見えるかもしれない。しかし、図面保存という「人間が介入するイベント」のコンテキストにおいて、数ミリ秒のオーバーヘッドは無視できる。それよりも、プロパティIDのハードコーディングを避け、文字列ベースでメタデータを走査する「柔軟な検知」の方が、OSアップデートに対するレジリエンス(回復力)が高い。

5. 結論

デジタル署名の検証は、単なる機能追加ではない。それは、エンジニアリング・データの「信頼の連鎖(Chain of Trust)」を維持するための防波堤である。

本稿で示した手法は、レガシーなVBA環境においても、Windows APIの力を借りることで現代的なセキュリティ要件を満たすことができる。技術の真髄は、新しいツールを追いかけることではなく、既存のアーキテクチャの限界を知り、その境界線をいかにして拡張するかにある。

実装の責任は、コードを書く者ではなく、その設計を統括するアーキテクトにある。

タイトルとURLをコピーしました