עטיפת מפתח באמצעות OpenSSL ב-Linux

במאמר הזה נסביר איך לארוז מפתח באופן ידני לפני ייבוא המפתח ל-Cloud KMS. צריך לפעול לפי ההוראות שבמאמר הזה רק אם לא רוצים להשתמש ב-Google Cloud CLI כדי להצפין את המפתח באופן אוטומטי לפני הייבוא. לסקירה כללית של ההבדלים, אפשר לעיין במאמר איך מתבצע ייבוא מפתחות.

אפשר לבצע את השלבים במאמר הזה תוך 5 עד 10 דקות, לא כולל השלבים שבקטע לפני שמתחילים.

לפני שמתחילים

לפני שמצפינים מפתח, צריך לוודא שמתקיימות הדרישות המוקדמות הבאות.

  1. יצירת אוסף מפתחות ומפתח ליעד, ויצירת משימת ייבוא.
  2. מוודאים שהמפתח זמין באופן מקומי ושהפורמט שלו נכון לייבוא ל-Cloud KMS.
  3. החלת תיקון (patch) והידור מחדש של OpenSSL

אחזור מפתח העטיפה

בקטע הזה מוסבר איך לאחזר את מפתח העטיפה מעבודת הייבוא שיצרתם בקטע לפני שמתחילים. מומלץ להשתמש במסוף Google Cloud .

המסוף

  1. נכנסים לדף Key Management במסוף Google Cloud .

    כניסה לדף Key Management

  2. לוחצים על השם של אוסף המפתחות שמכיל את עבודת הייבוא.

  3. לוחצים על הכרטיסייה Import Jobs (פעולות ייבוא) בחלק העליון של הדף.

  4. לוחצים על אפשרויות נוספות , ואז על הורדת מפתח העטיפה בתפריט הקופץ.

‫CLI של gcloud

כדי לוודא שמשימת הייבוא פעילה, מריצים את הפקודה gcloud kms import-jobs describe:

gcloud kms import-jobs describe IMPORT_JOB \
  --location LOCATION \
  --keyring KEY_RING \
  --format="value(state)"
state: ACTIVE

מריצים את הפקודה הבאה כדי לשמור את המפתח הציבורי ממשימת הייבוא ב-${HOME}/wrapping-key.pem

gcloud kms import-jobs describe \
  --location=LOCATION \
  --keyring=KEY_RING \
  --format="value(publicKey.pem)" \
  IMPORT_JOB > ${HOME}/wrapping-key.pem

API

  1. מבצעים קריאה ל-method‏ ImportJob.get.

  2. שולפים את המפתח הציבורי דרך השדה publicKey בתגובת ImportJob.get. הערך הזה הוא מסוג WrappingPublicKey. השדה pem מהסוג WrappingPublicKey הוא המפתח הציבורי בקידוד בפורמט PEM (דואר עם פרטיות משודרגת).

מידע נוסף על פורמט PEM זמין ב-RFC 7468, במיוחד בקטעים General Considerations ו-Textual Encoding of Subject Public Key Info.

הגדרה של משתני סביבה

פקודות OpenSSL דורשות כמה נתיבי קבצים כערכי קלט. כדי להקל על הפעלת הפקודות, מגדירים משתני סביבה לנתיבי הקבצים. חשוב לוודא שיש לכם הרשאת כתיבה לספריות שמוגדרות בהמשך.

  1. מגדירים את המשתנה PUB_WRAPPING_KEY לנתיב המלא של מפתח העטיפה שהורדתם מעבודת הייבוא. מפתח העטיפה מסתיים ב-.pem.

    PUB_WRAPPING_KEY="WRAPPING_KEY_PATH"
    

  2. מגדירים את המשתנה TARGET_KEY לנתיב המלא של המפתח שלא עבר פענוח (מפתח היעד).

    TARGET_KEY=TARGET_KEY_PATH
    

    מחליפים את הערך TARGET_KEY_PATH בנתיב לקובץ .bin של מפתחות סימטריים או בנתיב לקובץ .der של מפתחות אסימטריים.

  3. אם משתמשים ב-RSA-AES, מגדירים את המשתנה TEMP_AES_KEY לנתיב המלא למפתח ה-AES הזמני.

    TEMP_AES_KEY=TEMP_AES_KEY_PATH
    

  4. מגדירים את המשתנה WRAPPED_KEY לנתיב המלא שבו רוצים לשמור את מפתח היעד העטוף שמוכן לייבוא.

    WRAPPED_KEY=WRAPPED_KEY_PATH
    

  5. מוודאים שכל משתני הסביבה מוגדרים בצורה נכונה באמצעות הפקודות הבאות:

    echo "PUB_WRAPPING_KEY: " ${PUB_WRAPPING_KEY}; \
    echo "TARGET_KEY: " ${TARGET_KEY}; \
    echo "TEMP_AES_KEY: " ${TEMP_AES_KEY}; \
    echo "WRAPPED_KEY: " ${WRAPPED_KEY}
    

אחרי שהמשתנים מוגדרים בצורה נכונה, אפשר לעטוף את המפתח. יש שתי גישות, כפי שמתואר בהמשך: עם RSA בלבד או עם RSA-AES.

עוטפים את המפתח

עוטפים את המפתח באמצעות RSA

בגישה הזו, מפתח היעד עטוף בבלוק RSA. לכן, גודל מפתח היעד מוגבל. לדוגמה, אי אפשר להשתמש בשיטה הזו כדי להצפין מפתח RSA אחר. שיטות הייבוא הנתמכות הן rsa-oaep-3072-sha256 ו-rsa-oaep-4096-sha256.

  • עוטפים את מפתח היעד במפתח האריזה הציבורי באמצעות האלגוריתם CKM_RSA_PKCS_OAEP:

    openssl pkeyutl \
      -encrypt \
      -pubin \
      -inkey ${PUB_WRAPPING_KEY} \
      -in ${TARGET_KEY} \
      -out ${WRAPPED_KEY} \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:sha256 \
      -pkeyopt rsa_mgf1_md:sha256
    

עוטפים את המפתח באמצעות RSA-AES

בגישה הזו, מפתח היעד עטוף במפתח AES זמני. לאחר מכן מפתח ה-AES הזמני נארז באמצעות מפתח ה-RSA. שני המפתחות העטופים האלה משורשרים ומיוצאים. מכיוון שמפתח היעד מוצפן באמצעות AES ולא באמצעות RSA, אפשר להשתמש בגישה הזו כדי להצפין מפתחות גדולים. שיטות הייבוא הנתמכות הן rsa-oaep-3072-sha1-aes-256, ‏ rsa-oaep-4096-sha1-aes-256,‏ rsa-oaep-3072-sha256-aes-256 ו-rsa-oaep-4096-sha256-aes-256.

  1. יצירת מפתח AES רנדומלי זמני באורך 32 בייט ושמירתו במיקום שמזוהה על ידי ${TEMP_AES_KEY}:

    openssl rand -out "${TEMP_AES_KEY}" 32
    

  2. מצפינים את מפתח ה-AES הזמני באמצעות מפתח האריזה הציבורי, באלגוריתם CKM_RSA_PKCS_OAEP. אם שיטת הייבוא היא rsa-oaep-3072-sha1-aes-256 או rsa-oaep-4096-sha1-aes-256, משתמשים ב-sha1 בשביל rsa_oaep_md ו-rsa_mgf1_md. משתמשים ב-sha256 בשביל rsa-oaep-3072-sha256-aes-256 ו-rsa-oaep-4096-sha256-aes-256.

    openssl pkeyutl \
      -encrypt \
      -pubin \
      -inkey ${PUB_WRAPPING_KEY} \
      -in ${TEMP_AES_KEY} \
      -out ${WRAPPED_KEY} \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:{sha1|sha256} \
      -pkeyopt rsa_mgf1_md:{sha1|sha256}
    

  3. מגדירים את המשתנה OpenSSL_V110 לנתיב של סקריפט openssl.sh. אם פעלתם בדיוק לפי ההוראות לתיקון וקומפילציה מחדש של OpenSSL, תוכלו להשתמש בפקודה הזו בלי לשנות את ערך המשתנה.

    OPENSSL_V110="${HOME}/local/bin/openssl.sh"
    

  4. עוטפים את מפתח היעד במפתח ה-AES הזמני באמצעות האלגוריתם CKM_AES_KEY_WRAP_PAD ומצרפים אותו ל-WRAPPED_KEY.

    "${OPENSSL_V110}" enc \
      -id-aes256-wrap-pad \
      -iv A65959A6 \
      -K $( hexdump -v -e '/1 "%02x"' < "${TEMP_AES_KEY}" ) \
      -in "${TARGET_KEY}" >> "${WRAPPED_KEY}"
    

    הדגל -iv A65959A6 מגדיר את הערך A65959A6 כערך ההתחלתי החלופי. הדרישה הזו מופיעה במפרט RFC 5649.

המאמרים הבאים