
SRO PKCS11 – SSH Agent CNG هو وكيل ويندوز سيادي، فائق الخفة وبدون تبعيات، يدمج PKCS#11، SSH-agent، Pageant وCNG/Smartcard في ملف ثنائي واحد قوي. مصمم للبيئات المتطلبة، يوفر تشفيرًا ماديًا أصليًا، وعزل service/userland، ودعمًا كاملاً للبطاقات الذكية.
توحيد سيادي PKCS#11 + SSH-agent + Pageant + CNG/Smartcard
ملف تنفيذي واحد لنظام Windows يوحّد أربع وظائف كانت منفصلة تقليديًا:
سيادي. لا اعتماد على CRT. جميع عمليات الذاكرة تمر عبر RtlCopyMemory, RtlZeroMemory, RtlEqualMemory (FreeCRT.h). يونيكود في كل مكان (Win32 أصلي). لا malloc, memcpy, strlen, printf.
آمن. لا يتم تصدير المفاتيح الخاصة أبدًا. لا يمر أي رمز PIN. CNG/KSP تدير واجهة PIN الأصلية لنظام Windows. عزل صارم بين الخدمة ومساحة المستخدم عبر أنابيب (pipes) آمنة.
بسيط. ملف ثنائي واحد. لا مكتبات DLL خارجية. لا تضخم في السجل. تثبيت بسيط (regsvr32 أو -install).
متعدد الاستخدامات. دعم متزامن لـ PKCS#11 و SSH-agent و Pageant و WSL2 في نفس العملية.
---``` ┌──────────────────────────────────────────────────────────────┐ │ Clients (Git, VS, WSL, OpenSSH, PuTTY, Firefox) │ └────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────┼───────────────┬─────────────────┐ │ │ │ │ SSH-agent Pageant (WM_COPYDATA) PKCS#11 WSL2 (TCP) │ │ │ │ v v v v ┌──────────────────────────────────────────────────────────────┐ │ Service Stub (session 0, SYSTEM) │ │ - Accepte connexions sur \.\pipe\openssh-ssh-agent │ │ - Crée pipe interne par client (GUID unique) │ │ - Lance helper userland avec token interactif │ │ - Forwarde messages sans manipuler de secrets │ └────────────────────────┬─────────────────────────────────────┘ │ lancé par le service v ┌──────────────────────────────────────────────────────────────┐ │ Helper Userland (session interactive) │ │ - Connecte au pipe interne │ │ - Décode protocole SSH-agent/Pageant │ │ - Invoque CNG/KSP pour signature │ │ - UI PIN native Windows (pas de relay) │ │ - Renvoie signature au service │ │ - Fenêtre Pageant cachée pour WM_COPYDATA │ │ - Listener TCP 127.0.0.1:10022 pour WSL2 │ │ - Tray icon avec menu contextuel │ └────────────────────────┬─────────────────────────────────────┘ │ v ┌──────────────────────────────────────────────────────────────┐ │ CNG/KSP Backend │ │ - NCryptSignHash avec PKCS#1/PSS padding │ │ - Enumération certificats Windows Store │ │ - Filtrage SmartCardOnly / AllowedKSP │ │ - Support RSA + ECDSA (P-256, P-384, P-521) │ │ - Support EdDSA (Ed25519, Ed448) │ │ - Support Brainpool (P256r1, P384r1, P512r1) │ │ - Cache clés + providers (4h timeout) │ └──────────────────────────────────────────────────────────────┘
---
## أوضاع التنفيذ
### 1. وضع PKCS#11 (تلقائي)
يتم التحميل بواسطة:
- `ssh -I ssh-agent.exe user@host`
- Firefox (Security Devices → Load PKCS#11 Module)
- `pkcs11-tool --module ssh-agent.exe --list-objects`
يعرض النواتج القياسية لـ PKCS#11:
- `C_Initialize`, `C_Finalize`, `C_GetInfo`
- `C_GetSlotList`, `C_GetSlotInfo`, `C_GetTokenInfo`
- `C_GetMechanismList`, `C_GetMechanismInfo`
- `C_OpenSession`, `C_CloseSession`, `C_Login`, `C_Logout`
- `C_FindObjectsInit`, `C_FindObjects`, `C_FindObjectsFinal`
- `C_GetAttributeValue`
- `C_SignInit`, `C_Sign`
- `C_VerifyInit`, `C_Verify`
- `C_DecryptInit`, `C_Decrypt`
- `C_GenerateRandom`, `C_SeedRandom`
**الآليات المدعومة (14 إجمالاً):**
- `CKM_RSA_PKCS` (raw مع padding)
- `CKM_RSA_X_509` (raw بدون padding)
- `CKM_SHA1_RSA_PKCS` (ssh-rsa القديم)
- `CKM_SHA256_RSA_PKCS` (rsa-sha2-256)
- `CKM_SHA384_RSA_PKCS` (rsa-sha2-384)
- `CKM_SHA512_RSA_PKCS` (rsa-sha2-512)
- `CKM_SHA256_RSA_PKCS_PSS` (RSA-PSS SHA-256)
- `CKM_SHA384_RSA_PKCS_PSS` (RSA-PSS SHA-384)
- `CKM_SHA512_RSA_PKCS_PSS` (RSA-PSS SHA-512)
- `CKM_ECDSA` (raw)
- `CKM_ECDSA_SHA1` (قديم)
- `CKM_ECDSA_SHA256` (ecdsa-sha2-nistp256/384/521)
- `CKM_ECDSA_SHA384`
- `CKM_ECDSA_SHA512`
### 2. وضع الوكيل في مساحة المستخدم (مستقل)```bash
ssh-agent.exe
\\.\pipe\openssh-ssh-agent في جلسة المستخدممتوافق مع :
set SSH_AUTH_SOCK=\\.\pipe\openssh-ssh-agent)ssh-agent.exe -install net start SROSSHAgentCNG
- يعمل في جلسة 0 (SYSTEM)
- يقبل الاتصالات على أنبوب عمومي (pipe global)
- يُنشئ أنبوبًا داخليًا لكل عميل (مؤمن بواسطة SID)
- يُطلق مساعدًا في وضع المستخدم باستخدام `CreateProcessAsUserW`
- يُمرر الرسائل دون لمس الأسرار
- تجمّع مساعدين مع مهلة 4 ساعات (إعادة استخدام تلقائية)
- إزالة LRU إذا امتلأ التجمّع
**المزايا:**
- إدخال PIN للواجهة في جلسة المستخدم (وليس في الجلسة 0)
- متوافق مع البيئات المُشدّدة
- عزل صارم بين الخدمة والتشفير
- تعدد الإرسال متعدد المستخدمين
### 4. وضع المساعد المشفر في وضع المستخدم (userland)```bash
ssh-agent.exe -useragent -pipe \\.\pipe\ssh-ksp-helper-{GUID}
لانشأ تلقائيًا بواسطة الخدمة:
NCryptSignHash (واجهة PIN أصلية)regsvr32 ssh-agent.exe
أنشئ المفاتيح:
- `HKLM\SOFTWARE\San@sro Inc\PKCS11-SSH-Agent`
- `HKCU\SOFTWARE\San@sro Inc\PKCS11-SSH-Agent`
- `HKCU\SOFTWARE\Mozilla\Firefox\PKCS11Modules\SROSSHAgent`
### تثبيت خدمة Windows```bash
ssh-agent.exe -install
net start SROSSHAgentCNG
أضف إلى ~/.bashrc أو ~/.zshrc :```bash
export SSH_AUTH_SOCK="$HOME/.ssh/agent.sock"
if ! pgrep -u $USER socat > /dev/null || [ ! -S "$SSH_AUTH_SOCK" ]; then # Nettoyage préventif rm -f "$SSH_AUTH_SOCK"
# Lancement du bridge en arrière-plan
# Note: Utiliser 127.0.0.1 si mode 'mirrored'
# sinon l'IP du host (ex: 192.168.99.x)
socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork,unlink-early \
TCP:127.0.0.1:10022 > /dev/null 2>&1 &
fi
### إلغاء التثبيت```bash
regsvr32 /u ssh-agent.exe
ssh-agent.exe -remove
المفتاح: HKLM\SOFTWARE\San@sro Inc\pkcs11-cng أو HKCU\SOFTWARE\San@sro Inc\pkcs11-cng
مثال :``` StoreName = "MY" StoreLocation = "CurrentUser" SmartCardOnly = 1 AllowedKSP = "Microsoft Smart Card Key Storage Provider;YubiKey Smart Card Key Storage Provider" RelaxCheckMode = 0 LogLevel = 2
---
## البروتوكولات المدعومة
### SSH-Agent
#### SSH2_AGENTC_REQUEST_IDENTITIES (11)
طلب :```
[type=11]
الرد :``` [type=12][count][key_blob_1][comment_1][key_blob_2][comment_2]...
**key_blob RSA :**```
[len]["ssh-rsa"][len][exponent][len][modulus]
key_blob ECDSA :``` [len]["ecdsa-sha2-nistp256"][len]["nistp256"][len][point]
**key_blob EdDSA :**```
[len]["ssh-ed25519"][len][point]
طلب :``` [type=13][len][key_blob][len][data][flags]
**الأعلام :**
- `0x00` : ssh-rsa (SHA-1, legacy)
- `0x02` : rsa-sha2-256
- `0x04` : rsa-sha2-512
الرد :```
[type=14][len][signature_blob]
signature_blob :``` [len]["rsa-sha2-256"][len][signature_data]
### Pageant
متوافق مع PuTTY عبر `WM_COPYDATA` :
1. العميل ينشئ ذاكرة مشتركة عبر `CreateFileMapping`
2. يكتب طلب SSH-agent بالتنسيق القياسي
3. يرسل `WM_COPYDATA` إلى نافذة "Pageant"
4. يقرأ الرد من الذاكرة المشتركة
تنسيق الذاكرة المشتركة :```
[uint32 length][SSH-agent payload]
مستمع TCP على 127.0.0.1:10022 :
handle_ssh_message()يتولى Windows إدارة PIN بالكامل عبر CNG/KSP وبرنامج تشغيل البطاقة الذكية المصغر.
الوحدة لا تخزّن PIN أبداً ولا تراه أثناء العبور:
ذاكرة تخزين PIN المؤقتة: تُدار تلقائيًا بواسطة Windows/برنامج التشغيل المصغر (لا حاجة لذاكرة تخزين تطبيقية).
أعلام NCrypt :
NCRYPT_SILENT_FLAG (لا تظهر واجهة)SILENT_FLAG : إعادة محاولة تلقائية مع واجهة.ذاكرة تخزين المفاتيح المؤقتة (مهلة 4 ساعات):
CNG_KEY_INFO (مقبض، موفر، حاوية)ذاكرة تخزين المزوّدين المؤقتة (مهلة 4 ساعات):
NCRYPT_PROV_HANDLENCryptOpenStorageProvidercng_store_enum_certificates(cfg, callback, user_data);
المرشح:
- المفاتيح الخاصة المتاحة
- موفرو خدمة المفاتيح المعتمدون (إذا كان `SmartCardOnly`)
- المفاتيح غير القابلة للتصدير (إذا كان `SmartCardOnly`)
### التوقيع```c
cng_sign_hash(key_info, mechanism, hash, hash_len, signature, &sig_len);
الآلية → الحشو:
CKM_RSA_PKCS → BCRYPT_PAD_PKCS1CKM_SHA256_RSA_PKCS → BCRYPT_PAD_PKCS1 + BCRYPT_SHA256_ALGORITHMCKM_SHA256_RSA_PKCS_PSS → BCRYPT_PAD_PSS + حجم الملح = حجم التجزئةCKM_ECDSA_SHA256 → بدون حشو (توقيع خام)RSA :```c cng_cert_get_public_key(cert, modulus, &mod_len, exponent, &exp_len);
**ECDSA :**```c
cng_cert_get_ec_params(cert, params, ¶ms_len); // OID courbe
cng_cert_get_ec_point(cert, point, &point_len); // Point public
المنحنيات المدعومة:
nistp256 (OID: 1.2.840.10045.3.1.7), nistp384 (1.3.132.0.34), nistp521 (1.3.132.0.35)brainpoolP256r1, brainpoolP384r1, brainpoolP512r1ed25519 (OID: 1.3.101.112), ed448 (1.3.101.113)يدعم مصادقة Active Directory :```c cng_extract_upn_from_certificate(cert, upn, upn_size);
استخراج الامتداد `szOID_NT_PRINCIPAL_NAME` لاستخدامه كتعليق SSH.
---
## الأمان
### المفاتيح الخاصة
**لم يتم تصديرها أبدًا.** يتم تفويض جميع العمليات التشفيرية إلى CNG/KSP. يتم استدعاء `NCryptSignHash` مع مقبض المفتاح، وليس مع المفتاح نفسه.
### رمز PIN
**تتم إدارته حصريًا بواسطة Windows (CNG/KSP/minidriver).**
الوحدة **لا تخزن رمز PIN مطلقًا** و **لا تراه أثناء النقل** :
- لا يتم نقل رمز PIN أبدًا إلى وحدة PKCS#11
- يتم عرض واجهة PIN بواسطة برنامج تشغيل البطاقة الذكية المصغر
- يتم إدارة ذاكرة التخزين المؤقت لرمز PIN تلقائيًا بواسطة Windows/minidriver
- في وضع الخدمة: يتلقى المساعد في مساحة المستخدم (جلسة تفاعلية) واجهة PIN
**وضع الخدمة (تمرير خالص) :**
يقوم كعب الخدمة بعمل تمرير شفاف فقط:
- العميل ← الخدمة ← المساعد (تمرير رسالة وكيل SSH)
- المساعد ← الخدمة ← العميل (تمرير رد وكيل SSH)
- لا تقوم الخدمة بتحليل المحتوى مطلقًا
- لا ترى الخدمة أبدًا: رمز PIN، التجزئة، التوقيع، المفتاح
### عزل الخدمة ↔ مساحة المستخدم
**أنابيب آمنة.** كل أنبوب داخلي:
- يتم إنشاؤه باستخدام GUID فريد
- يتم إنشاؤه باستخدام `FILE_FLAG_FIRST_PIPE_INSTANCE`
- قائمة التحكم بالوصول التمييزية (DACL) تسمح فقط للمستخدم الحالي
يقوم المساعد في مساحة المستخدم باستدعاء CNG/KSP في الجلسة التفاعلية ← واجهة PIN أصلية.
### التدقيق
**سجلات Unicode.** يتم تسجيل جميع الأحداث عبر `utils_log()`:
- اتصالات العميل
- تعداد المفاتيح
- طلبات التوقيع
- أخطاء CNG/KSP
- تعارضات الوكلاء
**الموقع:** OutputDebugString + ملف اختياري (`utils_set_log_file()`).
---
## التوافق
| البيئة | الوضع | الحالة |
|------------------------------|------------------------|--------|
| OpenSSH for Windows | Standalone / Service | ✓ |
| Git for Windows | Standalone / Service | ✓ |
| Visual Studio | Standalone / Service | ✓ |
| WSL (npiperelay) | Standalone / Service | ✓ |
| WSL2 (TCP) | Standalone / Service | ✓ |
| PuTTY / plink / pscp | Pageant | ✓ |
| Firefox | PKCS#11 | ✓ |
| OpenSC / pkcs11-tool | PKCS#11 | ✓ |
| ssh -I (OpenSSH) | PKCS#11 | ✓ |
| البيئات المحصنة | Service stub | ✓ |
| البطاقة الذكية GIDS | CNG/KSP | ✓ |
| البطاقة الذكية PIV | CNG/KSP | ✓ |
| YubiKey | CNG/KSP | ✓ |
| Nitrokey | CNG/KSP | ✓ |
---
## تصدير المفاتيح العامة
### أمر CLI```bash
ssh-agent.exe -exportkey [output.pub]
CryptUIDlgSelectCertificateFromStoreOpenSSH :``` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5... [email protected]
**RFC4716 :**```
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "[email protected]"
AAAAB3NzaC1yc2EAAAADAQABAAABAQC5ABCDEF...
---- END SSH2 PUBLIC KEY ----
ترتيب الأولوية للتعليق:
TRAY_MODE_USERLAND (أخضر) :
TRAY_MODE_SERVICE (أزرق) :
تلميح ديناميكي:``` SRO SSH-Agent (Userland) 12 keys, 3 clients
تحديث:
- كل 5 ثوانٍ
- عند كل اتصال/فصل عميل
- عند مسح الذاكرة المخبأة
### القائمة السياقية
**Show Keys...** : حوار يسرد جميع المفاتيح المتاحة```
═══════════════════════════════════════════════
SRO SSH-Agent - Available Keys
═══════════════════════════════════════════════
[01] RSA-2048 - [email protected]
[02] ECDSA-nistp256 - [email protected]
[03] EdDSA-Ed25519 - [email protected]
═══════════════════════════════════════════════
Total: 3 keys
💡 Tip: Use 'Export Public Key' to copy SSH format
تصدير المفتاح العام... : يفتح مربع حوار التحديد وينسخ إلى الحافظة
مسح وإعادة تحميل المفاتيح : يمسح ذاكرة التخزين المؤقت للمفاتيح/الموفرين ويعيد التحميل
الإعدادات... : يعرض الإعدادات الحالية``` Current Configuration:
Store Name: MY Store Location: CurrentUser SmartCard Only: Yes Relax Key Usage Check Mode: No Log Level: 2
Edit registry to change: HKLM\SOFTWARE\San@sro Inc\pkcs11-cng
**Exit**: إيقاف نظيف (يشير إلى `g_shutdown_event`)
### مؤشر ترابط واجهة المستخدم المخصص
- نافذة مخفية مع مضخة الرسائل
- حلقة `GetMessage/DispatchMessage`
- حدث `g_tray_ready_event` للمزامنة
- تنظيف تلقائي (`Shell_NotifyIcon(NIM_DELETE)`)
---
## دعم WSL2
### البنية```
┌─────────────────────────────────────────────┐
│ WSL2 (Linux) │
│ - socat UNIX-LISTEN → TCP:127.0.0.1:10022 │
└─────────────────────────────────────────────┘
│
│ TCP
v
┌─────────────────────────────────────────────┐
│ Windows Host │
│ - ssh-agent.exe (listener 127.0.0.1:10022)│
│ - CNG/KSP → Smartcard │
└─────────────────────────────────────────────┘
الأمان:
g_wsl2_clients[16]CRITICAL_SECTION لكل فتحةالوضع المتطابق (Windows 11 22H2+):```bash
socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork,unlink-early
TCP:127.0.0.1:10022 > /dev/null 2>&1 &
**وضع NAT الكلاسيكي :**```bash
# Récupérer l'IP du host Windows
HOST_IP=$(ip route | grep default | awk '{print $3}')
socat UNIX-LISTEN:"$SSH_AUTH_SOCK",fork,unlink-early \
TCP:$HOST_IP:10022 > /dev/null 2>&1 &
BOOL wsl2_network_start(WORD port, HANDLE shutdown_event); void wsl2_network_stop(void); BOOL wsl2_network_is_running(void); DWORD wsl2_network_get_client_count(void);
---
## كشف النزاعات
### العوامل المكتشفة```c
typedef enum {
AGENT_NONE = 0,
AGENT_OPENSSH_NATIVE, // OpenSSH for Windows (ssh-agent.exe)
AGENT_PAGEANT, // PuTTY Pageant (fenêtre "Pageant")
AGENT_SRO_USERLAND, // SRO SSH-Agent userland
AGENT_SRO_SERVICE, // SRO SSH-Agent service Windows
AGENT_UNKNOWN // Agent inconnu détecté
} AGENT_TYPE;
OpenSSH الأصلي:
ssh-agent.exe عبر CreateToolhelp32SnapshotPageant:
FindWindowW(L"Pageant", L"Pageant")SRO Userland:
CreateFileW(\\.\pipe\openssh-ssh-agent)SRO Service:
OpenServiceW(L"SROSSHAgentCNG")SERVICE_RUNNINGيظهر عند بدء التشغيل إذا تم اكتشاف تعارض:``` ⚠ SSH Agent Conflict Detected
The following SSH agents are already running: • OpenSSH Native (ssh-agent.exe) • PuTTY Pageant
Running multiple agents may cause conflicts.
Do you want to continue anyway?
[Continue] [Stop conflicting agents] [Exit]
**الإجراءات:**
- **متابعة**: يشغّل رغم ذلك (خطر تعارض)
- **إيقاف**: يحاول إيقاف الوكلاء (إن أمكن)
- **خروج**: يخرج دون تشغيل
### الوظيفة العامة```c
BOOL detect_running_agents(AGENT_TYPE* detected_agents, DWORD* count);
BOOL show_agent_conflict_dialog(const AGENT_TYPE* agents, DWORD count);
const WCHAR* agent_type_to_string(AGENT_TYPE agent);
لا شيء. الملف الثنائي مكتفي ذاتيًا ولا يُحمّل سوى ملفات DLL للنظام:
kernel32.dll (موجود دائمًا)advapi32.dll (السجل، مدير التحكم بالخدمات)crypt32.dll (الشهادات)ncrypt.dll (CNG)bcrypt.dll (التجزئة)wtsapi32.dll (الجلسات)shell32.dll (أيقونة شريط المهام)ws2_32.dll (Winsock)cryptui.dll (حوار اختيار الشهادة)لا يوجد CRT. جميع عمليات الذاكرة عبر RtlCopyMemory، RtlZeroMemory، RtlEqualMemory.
SSH2_AGENTC_*_ENCRYPT).SSH2_AGENTC_ADD_ID_CONSTRAINED.MAX_HELPERS).RelaxCheckMode = 1 لاستخدامها.المساهمات مرحب بها! يُرجى:
هذا البرنامج مملوك لشركة San@sro inc.
ويُوزّع وفق نموذج ترخيص الثقة:
• الاستخدام الشخصي والتعليمي: مجاني ومُشجّع.
• الاستخدام المهني / التجاري: يتطلب شراء ترخيص السلام التقني.
الاستخدام في الشركات دون ترخيص صالح يُشكّل انتهاكًا لحقوق النشر،
رغم الغياب المتعمّد لأي قفل تقني.
يُسمح بإعادة التوزيع بشرط:
• بقاء الملف الثنائي سليمًا،
• الحفاظ على التوقيع Authenticode الأصلي.
هذا البرنامج مُقدَّم "كما هو"، دون أي ضمان من أي نوع.
الترخيص الكامل (بالفرنسية + الإنجليزية)، بما في ذلك التعريفات، شروط إعادة التوزيع، المدة، الإنهاء، وكيفية الحصول على ترخيص السلام التقني، متاح هنا:
للاستفسارات حول التراخيص المهنية:
📧 [email protected]
لا يتعامل SRO PKCS11 – SSH Agent CNG مع أي معلومات حساسة:
إدارة PIN والمفاتيح الخاصة والعمليات التشفيرية تتم بالكامل بواسطة Windows (CNG/KSP/minidriver).
للإبلاغ عن خطأ، سلوك غير طبيعي، أو ثغرة محتملة، هناك سياسة إفصاح مسؤول متاحة هنا:
جهة الاتصال الأمنية:
📧 [email protected]
SRO PKCS11 – SSH Agent CNG
سيادي. متين. عملي.
ملف ثنائي واحد يفعل كل شيء.
| القيمة | النوع | الوصف |
|---|
StoreName | REG_SZ | "MY"، "Root"، إلخ. (الافتراضي: "MY") |
StoreLocation | REG_SZ | "CurrentUser" أو "LocalMachine" |
Mode | REG_SZ | "All" أو "SmartCard" |
SmartCardOnly | REG_DWORD | 1 = تصفية البطاقات الذكية فقط |
AllowedKSP | REG_SZ | قائمة KSP المسموح بها (مفصولة بـ ";") |
RelaxCheckMode | REG_DWORD | 1 = تعطيل التحقق من EKU/KeyUsage/التواريخ (YubiKey PIV الموقّع ذاتيًا) |
LogLevel | REG_DWORD | 0=إيقاف، 1=خطأ، 2=معلومات، 3=تصحيح |