chore(deploy): обновление ИШ v107, keymedia, экспортёр QUIK, fail2ban для bj
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
# bj-validata-rebuild-gdbm SPRDIR
|
||||
# Пересобирает СОВМЕСТИМЫЙ справочник сертификатов (local.gdbm) из сертификатов,
|
||||
# вшитых в архивные local.pse + local.gdbm НРД. Формат НРД-gdbm не читается
|
||||
# gdbm-библиотекой («malformed»), но DER-сертификаты внутри — стандартный X.509.
|
||||
# Порядок критичен: leaf-серты → CA → CRL (иначе E070003A «нет доверенного»).
|
||||
# Справочник подписывается ключом с НОСИТЕЛЯ (нужен примонтированный ключевой
|
||||
# носитель + vdmkdev). Сборка во временной папке — провал не портит оригинал.
|
||||
set -uo pipefail
|
||||
VDLIB=/opt/Validata/VDCSP/lib/amd64
|
||||
ZPKI=/opt/Validata/VDCSP/bin/amd64/zpki1utl
|
||||
SPR="${1:?usage: bj-validata-rebuild-gdbm SPRDIR}"
|
||||
PSE="$SPR/local.pse"; GDBM="$SPR/local.gdbm"
|
||||
[ -f "$PSE" ] || { echo "{\"ok\":false,\"error\":\"нет $PSE\"}"; exit 1; }
|
||||
WORK=$(mktemp -d); trap 'rm -rf "$WORK"' EXIT
|
||||
cp "$PSE" "$WORK/local.pse"
|
||||
|
||||
# 1) извлечь серты (leaf=subject!=issuer первыми, CA=self-signed потом) + CRL
|
||||
EX=$(python3 - "$PSE" "$GDBM" "$WORK" <<'PY'
|
||||
import sys,subprocess,hashlib
|
||||
pse,gdbm,work=sys.argv[1],sys.argv[2],sys.argv[3]
|
||||
leaves={}; cas={}; crls={}
|
||||
for src in (pse,gdbm):
|
||||
try: data=open(src,'rb').read()
|
||||
except: continue
|
||||
i=0
|
||||
while i<len(data)-4:
|
||||
if data[i]==0x30 and data[i+1]==0x82:
|
||||
ln=(data[i+2]<<8)|data[i+3]; blob=data[i:i+4+ln]
|
||||
if len(blob)==4+ln:
|
||||
x=subprocess.run(['openssl','x509','-inform','DER','-noout','-subject','-issuer'],input=blob,capture_output=True)
|
||||
if x.returncode==0:
|
||||
o=x.stdout.decode()
|
||||
subj=[l for l in o.split(chr(10)) if l.startswith('subject')][0][7:]
|
||||
iss=[l for l in o.split(chr(10)) if l.startswith('issuer')][0][6:]
|
||||
(cas if subj==iss else leaves)[hashlib.md5(blob).hexdigest()]=blob
|
||||
elif subprocess.run(['openssl','crl','-inform','DER','-noout'],input=blob,capture_output=True).returncode==0:
|
||||
crls[hashlib.md5(blob).hexdigest()]=blob
|
||||
i+=1
|
||||
# внешние сертификаты НРД (напр. новый серт крипто-сервера) — берём только те, чей издатель уже есть среди CA хранилища
|
||||
import os,glob
|
||||
casubj=set()
|
||||
for b in cas.values():
|
||||
r=subprocess.run(['openssl','x509','-inform','DER','-noout','-subject'],input=b,capture_output=True); casubj.add(r.stdout.decode().strip()[8:])
|
||||
for f in sorted(glob.glob(os.environ.get('EXTRA_DIR','/var/lib/bj/.bj/nsd-certs')+'/*.cer')):
|
||||
b=open(f,'rb').read()
|
||||
if b[:2]!=b'\x30\x82':
|
||||
r=subprocess.run(['openssl','x509','-in',f,'-outform','DER'],capture_output=True); b=r.stdout
|
||||
x=subprocess.run(['openssl','x509','-inform','DER','-noout','-issuer'],input=b,capture_output=True)
|
||||
if x.returncode!=0: continue
|
||||
iss=x.stdout.decode().strip()[7:]
|
||||
if iss in casubj: leaves[hashlib.md5(b).hexdigest()]=b; print('extra:',os.path.basename(f),file=sys.stderr)
|
||||
else: print('extra skip (нет CA):',os.path.basename(f),file=sys.stderr)
|
||||
# исключить сертификаты по серийному номеру (напр. старый серт крипто-сервера НРД после смены ключа)
|
||||
excl={x.strip().upper().lstrip('0') for x in os.environ.get('EXCLUDE_SERIALS','').split(',') if x.strip()}
|
||||
if excl:
|
||||
for h in list(leaves):
|
||||
r=subprocess.run(['openssl','x509','-inform','DER','-noout','-serial'],input=leaves[h],capture_output=True)
|
||||
sn=r.stdout.decode().strip().split('=')[-1].upper().lstrip('0')
|
||||
if sn in excl: del leaves[h]; print('excluded serial:',sn,file=sys.stderr)
|
||||
n=0
|
||||
for h,b in leaves.items(): open(f"{work}/1leaf_{n}.der","wb").write(b); n+=1
|
||||
n=0
|
||||
for h,b in cas.items(): open(f"{work}/2ca_{n}.der","wb").write(b); n+=1
|
||||
# newest CRL: на каждого издателя оставить только самый свежий CRL — crestor падает
|
||||
# «имеется более новый САС» (E0700087), если после нового добавить старый
|
||||
import datetime
|
||||
best={}
|
||||
for h,b in crls.items():
|
||||
r=subprocess.run(['openssl','crl','-inform','DER','-noout','-issuer','-lastupdate'],input=b,capture_output=True)
|
||||
o=r.stdout.decode(errors='replace'); iss=[l for l in o.splitlines() if l.startswith('issuer')][0]
|
||||
lu=[l for l in o.splitlines() if l.startswith('lastUpdate')][0].split('=',1)[1].strip()
|
||||
try: t=datetime.datetime.strptime(lu,'%b %d %H:%M:%S %Y %Z')
|
||||
except Exception: t=datetime.datetime.min
|
||||
if iss not in best or t>best[iss][0]: best[iss]=(t,h)
|
||||
keep={h for _,h in best.values()}
|
||||
for h in list(crls):
|
||||
if h not in keep: print('dropped older CRL',file=sys.stderr); del crls[h]
|
||||
n=0
|
||||
for h,b in crls.items(): open(f"{work}/3crl_{n}.der","wb").write(b); n+=1
|
||||
print(f"{len(leaves)} {len(cas)} {len(crls)}")
|
||||
PY
|
||||
) || { echo "{\"ok\":false,\"error\":\"извлечение сертов не удалось\"}"; exit 1; }
|
||||
|
||||
CERTARGS=""; for c in "$WORK"/1leaf_*.der "$WORK"/2ca_*.der; do [ -f "$c" ] && CERTARGS="$CERTARGS -dercer $c"; done
|
||||
CRLARGS=""; for c in "$WORK"/3crl_*.der; do [ -f "$c" ] && CRLARGS="$CRLARGS -dercrl $c"; done
|
||||
[ -n "$CERTARGS" ] || { echo "{\"ok\":false,\"error\":\"сертификаты не извлечены ($EX)\"}"; exit 1; }
|
||||
|
||||
# 2) пересобрать gdbm во временной папке (ключ подписи стора — с носителя)
|
||||
OUT=$(LD_LIBRARY_PATH="$VDLIB" "$ZPKI" -minimal -tools -crestor \
|
||||
-uripse "pse://signed//$WORK/local.pse" -uriloc "file://$WORK/local.gdbm" \
|
||||
$CERTARGS $CRLARGS 2>&1)
|
||||
if ! echo "$OUT" | grep -qi 'Результат: OK'; then
|
||||
ERR=$(echo "$OUT" | grep -iE 'ошибк|Результат' | head -1 | tr -d '"')
|
||||
echo "{\"ok\":false,\"error\":\"crestor: $ERR\"}"; exit 1
|
||||
fi
|
||||
[ -f "$WORK/local.gdbm" ] || { echo "{\"ok\":false,\"error\":\"gdbm не создан\"}"; exit 1; }
|
||||
|
||||
# 3) положить пересобранные на место (атомарно)
|
||||
cp "$WORK/local.gdbm" "$GDBM.new" && mv "$GDBM.new" "$GDBM"
|
||||
cp "$WORK/local.pse" "$PSE.new" && mv "$PSE.new" "$PSE"
|
||||
echo "{\"ok\":true,\"leaf\":${EX% * *},\"crl\":${EX##* }}"
|
||||
Reference in New Issue
Block a user