İçeriğe geç
academia.sh

Ders 08 / 16

Sertifikalar ve Güven Zinciri

Bir adın bir açık anahtara bağlanması, zincirin güven çıpasına kadar yerel yürütülmesi ve bu kararın gidiş–dönüş bütçesine hiç dokunmaması.

İçindekiler

Önceki ders kurulumun bir ortak sır ürettiğini gösterdi ve o sırrın kaç tura mal olduğunu saydı. Üretilen şeyin adı sırdı; kimlik değildi. İstemci karşı ucun açık değerini aldı, onunla ortak bir sayıya vardı ve gövdeyi o sayıyla kapattı — ama karşı ucun ölçüm istasyonu olduğunu söyleyen hiçbir şey yoktu. Açık değeri gönderen taraf istasyon.ornek de olabilir, o adı kullanan başka bir uç da.

Bu dersin sorusu, bir adın bir açık anahtara nasıl bağlandığı ve istemcinin bu bağı doğrularken kaç kez soru sorduğudur. İkinci yarısı kursun eksenidir: zincir doğrulaması fazladan bir gidiş–dönüş olmadan alınan bir karardır, ve zincir uzasa da bu değişmez.

Sertifikanın Bildirdiği

Sertifika, bir adı bir açık anahtara bağlayan ve bu bağın altına başka birinin imzasını koyan bir bildirimdir. Alanları şunu söyler:

sertifika
  konu         : istasyon.ornek            <- ad kimin
  açık anahtar : <konunun açık anahtarı>   <- o adla hangi anahtar konuşur
  veren        : ara-1.ornek               <- bağı kim onayladı
  geçerlilik   : başlangıç .. bitiş        <- bağ ne zaman aralığında geçerli
  imza         : verenin gizli anahtarıyla üretilmiş

Bu döküm çalıştırılmaz; alanların ne bildirdiğini gösterir. Sertifikayı çıkaran kuruluşa sertifika otoritesi (certificate authority) denir.

Aracının konumu buradan tanıdıktır: yine iletide yazana bakılıyor. Fark tek bir alandadır — burada iletide yazanı doğrulayan bir şey vardır: imza. Kursun geri kalanında “aracı bildirime inanır” derken kastedilen şey, bu doğrulamanın olmamasıdır.

İmza Ne Kanıtlar

Aşağıdaki imza düzeneği ders içinde modellenmiştir. Gerçek bir imza şeması değildir ve hiçbir güvenlik özelliği taşımaz: modülüs küçültülmüştür, özet işlevi bir oyuncaktır ve bu modelde açık anahtardan gizli anahtar geri elde edilebilir. Şemaların güvenlik gerekçesi Kimlik, Erişim ve Kriptografi kursunun konusudur. Burada modelden alınan tek şey imzanın hangi alanların üzerinde durduğudur.

from math import gcd

TOHUM = 20260809
ASAL = 2147483647          # ders içinde küçültülmüş modülüs


def uretec(tohum: int):
    d = tohum % 2147483646 + 1

    def r(n: int) -> int:
        nonlocal d
        d = (d * 48271) % ASAL
        return d % n
    return r


def ozet(metin: str) -> int:
    h = 2166136261
    for b in metin.encode():
        h = (h * 16777619 + b) % ASAL
    return h


def anahtar_cifti(r) -> tuple[int, int]:
    while True:
        gizli = 3 + r(ASAL - 4)
        if gcd(gizli, ASAL - 1) == 1:
            return gizli, pow(gizli, -1, ASAL - 1)


def imzala(konu: str, acik: int, veren: str, veren_gizli: int, gecerli: bool) -> dict:
    s = {"konu": konu, "acik": acik, "veren": veren, "gecerli": gecerli}
    s["imza"] = pow(ozet(f"{konu}|{acik}|{veren}|{gecerli}"), veren_gizli, ASAL)
    return s


def imza_dogru(s: dict, veren_acik: int) -> bool:
    return pow(s["imza"], veren_acik, ASAL) == ozet(
        f"{s['konu']}|{s['acik']}|{s['veren']}|{s['gecerli']}")


r = uretec(TOHUM)
cipa_gizli, cipa_acik = anahtar_cifti(r)
yaprak_gizli, yaprak_acik = anahtar_cifti(r)
yaprak = imzala("istasyon.ornek", yaprak_acik, "cipa.ornek", cipa_gizli, True)

print(f"konu {yaprak['konu']}, veren {yaprak['veren']}")
print(f"imza doğru mu: {imza_dogru(yaprak, cipa_acik)}")
print(f"konusu değiştirilmiş kopya: {imza_dogru(dict(yaprak, konu='baska.ornek'), cipa_acik)}")
print(f"anahtarı değiştirilmiş kopya: {imza_dogru(dict(yaprak, acik=7), cipa_acik)}")
konu istasyon.ornek, veren cipa.ornek
imza doğru mu: True
konusu değiştirilmiş kopya: False
anahtarı değiştirilmiş kopya: False

İmza konunun, açık anahtarın, verenin ve geçerlilik alanının üzerinde durur; alanlardan biri değişirse doğrulama düşer. Bunun sonucu ince ama önemlidir: imza sertifikayı değiştirilmez kılmaz, değiştirildiğini belli eder.

İmzanın doğrudan belgenin üzerinde değil, belgenin özeti üzerinde durduğu da eklenmelidir. Bu, imzalanacak şeyin uzunluğunu sabitler ve imza işini belgenin boyundan bağımsız kılar — önceki dersteki iş bölümünün aynısı, asimetrik rol yine sabit boyutlu bir sayıya dokunur. Karşılığında yeni bir koşul doğar: iki farklı belgenin aynı özete düşmemesi gerekir. Bu koşulun hangi varsayımla sağlandığı Kimlik, Erişim ve Kriptografi kursunun konusudur.

İmzanın kanıtlamadıkları da sayılmalıdır. İmza, verenin bu bağı onayladığını gösterir; verenin onaylamaya yetkili olduğunu göstermez. Konunun o anda hâlâ var olduğunu göstermez. Konunun gizli anahtarının başkasının eline geçmediğini de göstermez. Bunların hepsi sertifikanın dışında olup bitmiş şeylerdir ve imzalanmış bir belgeye sonradan yazılamaz.

Zincir ve Güven Çıpası

İmzayı doğrulamak için verenin açık anahtarı gerekir. O anahtarın verene ait olduğunu ne söyler? Başka bir sertifika. Bu soru kendini yineler ve sertifika zinciri doğar: en altta konuyu taşıyan yaprak sertifika, üstünde bir ya da birkaç ara sertifika, en üstte zincirin durduğu yer.

Zincir bir yerde durmak zorundadır ve durduğu yer bir imzayla değil, bir yerleşimle belirlenir. İstemcinin elinde önceden bulunan, başka hiçbir şeye karşı doğrulanmayan sertifikaya güven çıpası (trust anchor) denir. Çıpa kendinden imzalı (self-signed) olabilir, çoğunlukla öyledir; ama onu güvenilir yapan kendi imzası değildir — kendi imzası hiçbir şey söylemez. Onu güvenilir yapan istemcinin elinde olmasıdır.

Bu ayrım kursun eksenine doğrudan bağlanır. Çıpa istemcinin yanındadır, ağın ucunda değil. Yani zincirin en üst basamağı için bile kimseye soru sorulmaz.

Zinciri kim taşır sorusunun yanıtı da tur bütçesini belirler. Yaprak ve ara sertifikaları sunucu gönderir; çıpayı istemci tutar. İstemcinin zinciri toplamak için ayrıca bir istek yapması gerekmez, çünkü zincir zaten sunumun içinde gelir. Sunucunun ara sertifikaları eksik göndermesi ise istemciyi tur harcamaya değil, doğrudan redde iter: elindeki parçalar çıpaya varmıyorsa istemci kararını verir.

Adın Eşleştirilmesi

Zincir tutarlı olsa bile karar bir eşleştirmeye daha bağlıdır: istemcinin gitmek istediği ad, sertifikanın bildirdiği adlardan birini karşılamalıdır. X.509 sertifikaları bu adları alternatif ad alanında taşır; bir sertifika birden çok ad bildirebilir ve joker biçim (*.istasyon.ornek gibi) tek bir seviyeyi karşılar.

Eşleştirmenin iki özelliği kursun eksenine bağlanır. Birincisi, eşleştirme de yereldir: istemci elindeki adı elindeki listeyle karşılaştırır, kimseye sormaz. İkincisi ve daha incesi, karşılaştırmanın iki ucu ayrı kaynaklardan gelmek zorundadır. İstenen ad istemcinin kendi isteğinden gelir, bildirilen ad sertifikadan. Ad sertifikadan okunup yine sertifikayla karşılaştırılırsa denetim her zaman geçer ve hiçbir şey ölçmez — denetimin anlamı, iki ucun bağımsızlığındadır.

Zincir Doğrulaması Tur İstemez

Kırk sertifika sunumu ölçülüyor. Zincir uzunlukları bir ile beş arasında değişiyor; kimi sunumun bir halkasının imzası bozuk, kiminin zinciri istemcinin çıpalarına varmıyor, kiminin yaprak konusu istenen adı karşılamıyor, kiminin geçerlilik alanı kapalı. Kâhin — kurguyu biz ürettiğimiz için bilinen gerçek — her sunum için kabulün doğru olup olmadığını söylüyor. Her sunum tek bir karar taşıyor, yani küme 40 karardır ve çözünürlüğü 1/40 = 0,025’tir.

Ölçümün varsayımları:

  • GT7 — İmza şeması ders içinde modellenmiştir: modülüs küçültülmüş, özet işlevi bir oyuncaktır ve bu modelde açık anahtardan gizli anahtar geri elde edilebilir. Ölçülen şey imzanın gücü değil, doğrulamanın nerede yapıldığıdır.
  • GT8 — Kırk sunum tek bir tohumdan üretilir; zincir uzunluğu bir ile beş arasında çekilir ve her sunuma en çok bir kusur yazılır: bozuk imza, çıpaya varmayan zincir, istenen adı karşılamayan konu, kapanmış geçerlilik alanı ya da iptal.
  • GT9 — Kâhin kurguyu biz ürettiğimiz için bilinir: bir sunumun kabulü ancak kusuru yoksa doğrudur. İptal kusuru zincirin içine yazılmaz — o zincirler baştan sona tutarlıdır ve doğrulama iptali göremez.
  • GT10 — Yaprak ve ara sertifikaları sunucu gönderir, güven çıpasını istemci tutar; zinciri toplamak için ayrıca istek yapılmaz. Çıpa kümesi tektir.
  • GT11 — Üç rejim karşılaştırılır: yerel çıpayla yürüme, her halkayı verenine sorma (halka başına bir gidiş–dönüş), doğrulamayı hiç yapmama. Yürüyüş erken çıkar: bozuk bir halkada durur, bu yüzden imza doğrulaması sayısı halka sayısına eşit olmaz.
  • GT12 — Ölçülen karar aracının değil istemcinindir; aracı bu tabloya girmez. Sayılan şey bir süre değil, doğrulama adımı ve gidiş–dönüştür.
from math import gcd

TOHUM = 20260809
ASAL = 2147483647
KUSURLAR = ("yok", "yok", "yok", "yok", "yok", "yok", "yok",
            "imza", "cipa", "ad", "sure", "iptal", "iptal")


def uretec(tohum: int):
    d = tohum % 2147483646 + 1

    def r(n: int) -> int:
        nonlocal d
        d = (d * 48271) % ASAL
        return d % n
    return r


def ozet(metin: str) -> int:
    h = 2166136261
    for b in metin.encode():
        h = (h * 16777619 + b) % ASAL
    return h


def anahtar_cifti(r) -> tuple[int, int]:
    while True:
        gizli = 3 + r(ASAL - 4)
        if gcd(gizli, ASAL - 1) == 1:
            return gizli, pow(gizli, -1, ASAL - 1)


def imzala(konu: str, acik: int, veren: str, veren_gizli: int, gecerli: bool) -> dict:
    s = {"konu": konu, "acik": acik, "veren": veren, "gecerli": gecerli}
    s["imza"] = pow(ozet(f"{konu}|{acik}|{veren}|{gecerli}"), veren_gizli, ASAL)
    return s


def imza_dogru(s: dict, veren_acik: int) -> bool:
    return pow(s["imza"], veren_acik, ASAL) == ozet(
        f"{s['konu']}|{s['acik']}|{s['veren']}|{s['gecerli']}")


def zincir_uret(uzunluk: int, ad: str, r, cipa_gizli: int, gecerli: bool) -> list[dict]:
    ust_gizli, ust_ad, zincir = cipa_gizli, "cipa.ornek", []
    for basamak in range(uzunluk, 0, -1):
        gizli, acik = anahtar_cifti(r)
        konu = ad if basamak == 1 else f"ara-{basamak - 1}.ornek"
        zincir.append(imzala(konu, acik, ust_ad, ust_gizli, gecerli or basamak > 1))
        ust_gizli, ust_ad = gizli, konu
    return zincir


def zincir_dogrula(zincir: list[dict], ad: str, cipalar: dict, sayac: dict) -> bool:
    ust_acik = cipalar.get(zincir[0]["veren"])
    if ust_acik is None:
        return False
    for s in zincir:
        sayac["imza"] += 1
        if not imza_dogru(s, ust_acik) or not s["gecerli"]:
            return False
        ust_acik = s["acik"]
    return zincir[-1]["konu"] == ad


r = uretec(TOHUM)
cipa_gizli, cipa_acik = anahtar_cifti(r)
CIPALAR = {"cipa.ornek": cipa_acik}

sunumlar = []
for no in range(40):
    uzunluk, kusur = 1 + r(5), KUSURLAR[r(13)]
    ad = "baska.ornek" if kusur == "ad" else "istasyon.ornek"
    zincir = zincir_uret(uzunluk, ad, r, cipa_gizli, kusur != "sure")
    if kusur == "imza":
        zincir[-1] = dict(zincir[-1], imza=(zincir[-1]["imza"] + 1) % ASAL)
    elif kusur == "cipa":
        zincir[0] = dict(zincir[0], veren="bilinmeyen.ornek")
    sunumlar.append({"uzunluk": uzunluk, "kusur": kusur, "zincir": zincir})


def olc(sunumlar, tur_basina, dogrula=True):
    sayac, dogru, yanlis, tur = {"imza": 0}, 0, 0, 0
    for s in sunumlar:
        verilen = (zincir_dogrula(s["zincir"], "istasyon.ornek", CIPALAR, sayac)
                   if dogrula else True)
        dogru += verilen == (s["kusur"] == "yok")
        yanlis += verilen != (s["kusur"] == "yok")
        tur += tur_basina * s["uzunluk"]
    return dogru, yanlis, tur, sayac["imza"]


print(f"{'rejim':<26s} {'doğru':>6s} {'yanlış':>7s} {'gidiş–dönüş':>12s} "
      f"{'imza doğrulaması':>17s}")
for ad_rejim, tur_basina, dgr in (("yerel çıpa", 0, True),
                                  ("her halkayı uzaktan sorma", 1, True),
                                  ("doğrulamayı atlama", 0, False)):
    d, y, t, i = olc(sunumlar, tur_basina, dgr)
    print(f"{ad_rejim:<26s} {d:6d} {y:7d} {t:12d} {i:17d}")

print()
print(f"{'zincir uzunluğu':>15s} {'sunum':>6s} {'imza doğrulaması':>17s} "
      f"{'gidiş–dönüş':>12s}")
for u in range(1, 6):
    esler = [s for s in sunumlar if s["uzunluk"] == u]
    print(f"{u:15d} {len(esler):6d} {olc(esler, 0)[3]:17d} {0:12d}")

print()
kusurlar = {k: sum(s["kusur"] == k for s in sunumlar) for k in
            ("yok", "imza", "cipa", "ad", "sure", "iptal")}
print(f"sunum {len(sunumlar)}, karar {len(sunumlar)}, "
      f"halka {sum(s['uzunluk'] for s in sunumlar)}, kusur {kusurlar}")
rejim                       doğru  yanlış  gidiş–dönüş  imza doğrulaması
yerel çıpa                     33       7            0                98
her halkayı uzaktan sorma      33       7          111                98
doğrulamayı atlama             17      23            0                 0

zincir uzunluğu  sunum  imza doğrulaması  gidiş–dönüş
              1      9                 9            0
              2     10                18            0
              3     10                24            0
              4      3                12            0
              5      8                35            0

sunum 40, karar 40, halka 111, kusur {'yok': 17, 'imza': 3, 'cipa': 4, 'ad': 5, 'sure': 4, 'iptal': 7}

İlk iki satır kursun eksenini tek başına ödüyor. Yerel çıpayla yürüyen istemci 33 kararı doğru, 7’sini yanlış aldı ve bunu sıfır gidiş–dönüşle yaptı. Her halkayı verenine soran istemci 111 gidiş–dönüş harcadı ve aynı 33 doğru, 7 yanlış tablosuna vardı. Sormak tek bir kararı değiştirmedi; yalnız 111 tur ekledi.

İkinci tabloda gidiş–dönüş sütunu baştan sona sıfırdır. Zincir bir halkayken de beş halkayken de istemci kimseye sormaz; artan tek şey yerel iştir — imza doğrulaması 9’dan 35’e çıkar. Yerel iş ile tur arasındaki fark budur: biri istemcinin işlemcisinde, öbürü ağın üzerinde ödenir ve ikisi aynı birime çevrilemez.

Toplam imza doğrulaması 98, halka sayısı 111. Aradaki fark bir tutarsızlık değil, yürüyüşün kendisidir: çıpaya varmayan dört zincirde hiçbir imza doğrulanmaz — istemci daha ilk adımda elinde çıpa olmadığını görür — ve bozuk bir halkaya rastlandığında yürüyüş orada durur. Zincir doğrulaması erken çıkan bir işlemdir.

Zincirin Söylemediği

Yanlış çıkan 7 kararın hepsi aynı kusurdan gelir ve tablonun son satırında adı yazılıdır: iptal 7. Bu yedi sunumda zincir baştan sona tutarlıdır — imzalar birbirini tutar, ad istenendir, geçerlilik alanı açıktır — ama sertifika artık geçerli sayılmamaktadır.

Ayrım şudur: zincir doğrulaması belgenin iç tutarlılığını ölçer ve ölçtüğü her şey belgenin içinde yazılıdır. Bu yüzden yerel yürüyebilir ve bu yüzden tur istemez. İptal ise belgenin dışında olan biteni bildirir ve belgeye sonradan yazılamaz, çünkü belge imzalandığı anda donar. Zincir sormadan doğrulanır; iptal sorulmadan bilinemez.

Bu yedi karar bir tur borcudur. Borcun nasıl ödendiği, ödemenin kaç tura mal olduğu ve ödememenin ne bıraktığı bu konunun son dersinde sayılacak.

Yapılandırma Kusurları ve Daraltmalar

Tablonun üçüncü satırı bir kusurun bedelidir. Zincir doğrulamasını hiç yapmayan istemci sıfır tur ve sıfır imza doğrulamasıyla kurtulur; ödediği şey, doğru karar sayısının 33’ten 17’ye inmesidir. Yanlış olan budur — kazanılan iş yereldir ve ucuzdur, kaybedilen ise kararın kendisidir. Bunun nasıl yapıldığı bu kursun konusu değildir.

Doğrulamanın parçaları da ayrı ayrı sayılmalı ve her birinin yanına daraltması yazılmalıdır:

  • Ad denetimi. Ölçümde 5 sunum yalnız bu denetim yüzünden reddedildi: zincirleri kusursuzdu, konuları istenen adı karşılamıyordu. Daraltma: ad denetimi yapılandırmayla açılıp kapanan bir seçenek değil, doğrulama yolunun ayrılmaz adımı olarak kurulursa kapatılamaz.
  • Geçerlilik denetimi. Ölçümde 4 sunum yalnız bu yüzden reddedildi. Daraltma: geçerlilik aralıkları kısa tutulursa yanlış bir saatin açtığı pencere de kısalır.
  • Çıpa kümesinin genişliği. İstemcinin elindeki her çıpa, o çıpadan inen her zinciri kabul edilebilir kılar. Daraltma: çıpa kümesi gerçekten kullanılan uçlara göre daraltılırsa kabul edilebilir zincir kümesi de aynı oranda daralır.
  • Zincirin ara halkaları. Ölçümde 4 sunum çıpaya hiç varmadı ve bu yüzden reddedildi; sunucunun ara sertifikaları eksik göndermesi de aynı sonucu doğurur. Daraltma: eksik halka istemcide değil sunucu yapılandırmasında kapatılır — istemcinin çıpa kümesini genişleterek değil.

Son madde bir alışkanlığı da açıklar: “sertifika hatası” görünen durumların çoğu bir saldırı değil, bir yapılandırma kusurudur. Kusurun nerede olduğu, hangi denetimin düştüğüne bakılarak ayrılır.

Özet

  • Sertifika bir adı bir açık anahtara bağlar ve bağın altına verenin imzasını koyar; imza konu, anahtar, veren ve geçerlilik alanlarının üzerinde durur.
  • İmza belgeyi değiştirilmez kılmaz, değiştirildiğini belli eder; verenin yetkili olduğunu, konunun hâlâ var olduğunu ve anahtarın elde kaldığını göstermez.
  • Zincir güven çıpasında durur; çıpayı güvenilir yapan kendi imzası değil, istemcinin elinde bulunmasıdır.
  • Kırk sunumda yerel çıpayla yürüyen istemci 33 doğru, 7 yanlış kararı 0 gidiş–dönüşle aldı; her halkayı soran istemci 111 gidiş–dönüş harcayıp aynı tabloya vardı.
  • Zincir uzunluğu 1’den 5’e çıkarken yerel imza doğrulaması 9’dan 35’e çıktı, gidiş–dönüş her satırda 0 kaldı.
  • Yanlış çıkan 7 kararın tamamı iptalden gelir: zincir belgenin içini ölçer, iptal belgenin dışında olan bitendir.

Sonraki Adım

Zincir doğrulaması hiç tur istemedi. Ama bu doğrulama havada durmaz: belirli bir bağlantının içinde, belirli bir anda yapılır ve sertifikanın istemciye ulaşması için önce bir alışverişin başlaması gerekir. O alışverişin kendi bütçesi vardır — kaç ileti gidip geliyor, sertifika hangi turda geliyor, gövde hangi turdan sonra taşınmaya başlıyor. Sonraki ders bu bütçeyi sayacak ve bütçenin kapanmasıyla birlikte aracının karar tablosuna ne olduğunu ölçecek.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat