Παρασκευή, 10 Ιουλίου 2009

Gcc09: Sha384withECDSA και openjdk (a detective story)

Άλλο ένα project που υλοποιήθηκε στα πλαίσια του GCC2009 ξεκίνησε με αφορμή ένα debian bug που μετατράπηκε σε openjdk (classpath) bug.

Το σύμπτωμα ήταν ότι το εργαλείο keytool της java αρνιόταν επίμονα να εισάγει (import) το certificate της εταιρείας COMODO παραπονούμενο ότι ο αλγόριθμος υπογραφών "ECDSAwithSHA384" δεν είναι διαθέσιμος. Αυτό είχε ως συνέπεια σχεδόν ολόκληρο το java stack του debian/ubuntu να μεταβαίνει στην κατάσταση FTBFS (fail to build from source) πράγμα φυσικά παράλογο, γι αυτό και το bug είχε σοβαρότητα "serious".

Λίγο πριν την έναρξη του camping, ο Matthias Klose (aka doko) έκλεισε το bug με ένα κατά τη γνώμη μου προσωρινό "workaround", σύμφωνα με το οποίο το ca-certificates πακέτο παύει πλέον να παραπονιέται όταν του ζητούν να εισάγει ένα certificate του οποίου ο αλγόριθμος υπογραφής δεν είναι διαθέσιμος. Φυσικά με αυτό τον τρόπο αυξάνουν οι πιθανότητες "έκπληξης" του χρήστη ο οποίος βλέπει ότι για κάποιο μυστήριο λόγο η java εφαρμογή του δεν εμπιστεύεται ένα site παρά το γεγονός ότι το certificate authority αυτού του site βρίσκεται στο /etc/ssl όπως θα έπρεπε.

Επειδή λοιπόν επιθυμία όλων μας πιστεύω ως χρήστες είναι να μειώνονται οι δυσάρεστες εκπλήξεις όσο περνάει ο καιρός αντί να αυξάνονται, τέθηκε η ιδέα της μόνιμης διόρθωσης του προβλήματος. H δουλειά λοιπόν ήταν κατά κύριο λόγο το λεγόμενο "triaging" του bug, να ρίξουμε φως δηλαδή στο μυστήριο του γιατί ο standard αυτός αλγόριθμος δεν ήταν διαθέσιμος αλλά και η διόρθωση του bug υλοποιώντας ό,τι βρούμε ότι λείπει, προκειμένου ο αλγόριθμος να δουλέψει.

Η πρόκληση έγινε κάπως μεγαλύτερη από το γεγονός ότι ούτε εγώ ούτε ο Κωστής Αναγνωστόπουλος με τον οποίο συνεργαστήκαμε σε αυτό το project δεν είχαμε εμπειρία από την εσωτερική δομή του openjdk, χρειαζόταν δηλαδή να εφαρμοστούν οι αρχές του "large scale code reading" που τόσο ωραία έχει περιγράψει ο κος Σπινέλλης στο βιβλίο του. (Τουλάχιστον κρίνοντας από τα samples και τα περιεχόμενα αφού ομολογώ ότι δεν το έχω διαβάσει :p. Από σήμερα πάντως θα το βάλω σίγουρα στο wish-list)

Το πρώτο βήμα ήταν λοιπόν η ανάγνωση του κώδικα του keytool και η κατασκευή ενός πολύ μικρού "testcase" (γύρω στις 5 γραμμές κώδικα), το οποίο παρουσίαζε το πρόβλημα απλοποιώντας το παράλληλα σε μεγάλο βαθμό. Από εκεί και πέρα γνωρίζαμε ότι εφόσον το testcase θα δούλευε, το πρόβλημα θα είχε λυθεί.

Έπειτα, συνεχίσαμε την ανάγνωση του κώδικα του openjdk χρησιμοποιώντας το eclipse (δηλαδή στο laptop του Κωστή εφόσον στο δικό μου δεν ήθελε ούτε το 3.5 ούτε το 3.4 να δουλέψει με καμμία δύναμη και εφόσον δεν είχαμε ουσιαστικά πρόσβαση στο δίκτυο έπρεπε να ξεχάσουμε και τις άλλες εκδόσεις). Η ιδέα ήταν να εντοπίσουμε και να "ιχνηλατήσουμε" (trace) το μονοπάτι εκτέλεσης στο οποίο φορτώνονται οι αλγόριθμοι υπογραφών, προκειμένου να ανακαλύψουμε πού βρίσκεται ο κώδικας αυτών των αλγορίθμων.

(Φυσικά και το πρόβλημα δεν είναι τόσο προφανές ώστε να λύνεται με μία find/grep. Οι providers μπορεί να βρίσκονται είτε σε αρχεία java είτε σε native βιβλιοθήκες που προσπελαύνονται μέσω JNI και η όλη διαδικασία συντονίζεται από αρχεία ρυθμίσεων που και αυτά βρίσκονται σε άλλο μέρος ανάλογα με τη διανομή. ΠΡΟΣΟΧΗ! όσοι έχετε διαβάσει ως εδώ, παρακαλώ ΜΗΝ πηδήξετε από το παράθυρο, τουλάχιστον όχι ακόμα, έχει και καλύτερο παρακάτω :p)

Μετά από μια μέρα συνεχούς χτυπήματος του κεφαλιού στον τοίχο λοιπόν, καθώς και το έξτρα ρίξιμο της ψυχολογίας από το να βλέπεις άλλες ομάδες να γράφουν ένα σωρό κώδικα στο ίδιο διάστημα :p ο Κωστής έφτασε στη ρίζα του προβλήματος ενώ εγώ ήδη ασχολούμουν με την υποστήριξη των ADSL modems (περισσότερα γι αυτό σε άλλο post). Σημαντικό είναι να παρατηρήσουμε ότι το πιο βοηθητικό στοιχείο ήταν τα runtime debug messages (Debug java-prop: java.security.debug={all|provider|sunpkcs11}) και όχι η στατική ανάλυση καθώς τόσα πολλά συστατικά του security framework καθορίζονται δυναμικά κατά το χρόνο εκτέλεσης.

Για καλή μας τύχη ανακαλύψαμε ότι το πρόβλημα υπάρχει εξίσου και στο sun jdk και έχει επιλυθεί σε μεγάλο βαθμό από τον Andreas Sterbenz. Η ιδέα είναι ότι η Java χρησιμοποιεί το PKCS11 διεθνές πρότυπο μεταξύ άλλων και για κρυπτογραφία ελλειπτικών καμπυλών (Elliptic curves) και μία βιβλιοθήκη που υλοποιεί αυτό το πρότυπο είναι η NSS (γνωστή λόγω του mozilla project). Αρκεί λοιπόν να συνδέσουμε τα δύο και είμαστε έτοιμοι.

Η σύνδεση επιτυγχάνεται φτιάχνοντας απλά ένα αρχείο ρυθμίσεων (/etc/java-6-openjdk/security/sunpkcs11-NSS.conf στο debian) με τα εξής περιεχόμενα:
    name = NSS
nssLibraryDirectory = /usr/lib
nssDbMode = noDb
attributes = compatibility
Μετά από αυτό, μπορούμε να προσθέσουμε το sun.security.pkcs11.SunPKCS11
security provider στο αρχείο /etc/java-6-openjdk/security/java.security προσθέτοντας απλά μία γραμμή ως εξής:

security.provider.9=sun.security.pkcs11.SunPKCS11 /etc/java-6-openjdk/security/sunpkcs11-NSS.conf
(το παραπάνω είναι μία γραμμή) και επιτέλους το testcase (και κατ' επέκταση το import του COMODO certificate) δούλεψε :)

Υπήρξε μόνο ένα πρόβλημα: πιθανότατα για λόγους κανονισμών της Aμερικής σχετικά με την εξαγωγή κρυπτογραφικών μεθόδων, ο κώδικας κρυπτογραφίας ελλειπτικών καμπυλών δεν είναι ενσωματωμένος στην προεπιλεγμένη ρύθμιση της βιβλιοθήκης NSS. Αυτό συμβαίνει ίσως και στη Fedora 11(αν και ομολογώ ότι δεν κοιτάξαμε το spec file της nss βιβλιοθήκης) με αποτέλεσμα να μην μπορεί να χρησιμοποιηθεί ο εν λόγω αλγόριθμος σε αυτή τη διανομή (πιθανόν να χρειαστεί bug report).

Στη Gentoo η μέθοδος δουλεύει με τη μικρή διαφορά ότι πρέπει να προβλέψουμε ότι η NSS βιβλιοθήκη βρίσκεται στο /usr/lib/nss και τα αρχεία ρυθμίσεων (π.χ., java.security) δε βρίσκονται στο /etc. Επίσης χρειάζεται το πακέτο dev-libs/nss-3.12.2. Τέλος, στη debian/ubuntu ο τρόπος αυτός δουλεύει αρκεί να είναι εγκατεστημένο το πακέτο libnss3-1d που περιέχει τη βιβλιοθήκη NSS.

Καταλήξαμε λοιπόν ότι το πρόβλημα έχει ήδη λυθεί και αρκεί η λύση αυτή να ενσωματωθεί στις διανομές. Για την ubuntu jaunty θα ανέβουν σύντομα πακέτα στο ppa μου που συμπεριλαμβάνουν αυτή τη λειτουργικότητα, ενώ θα γίνει συζήτηση και για ενσωμάτωση στη debian και από εκεί στην επόμενη έκδοση της ubuntu ίσως.

Το μεγαλύτερο δίδαγμα από αυτό το project ήταν ότι καμμιά φορά και το debugging/triaging ενός προβλήματος μπορεί να παρέχει αρκετές συγκινήσεις και σπαζοκεφαλιές οπότε οι triagers αξίζουν και αυτοί το σεβασμό μας :) Επίσης, μερικές φορές (όπως αυτήν) το triaging είναι το 98% της δουλειάς αφού η ίδια η επίλυση ήταν μόνο 10 γραμμές σε 2 configuration files τελικά.

Η συνεργασία με τον Κωστή ήταν τουλάχιστον εξαιρετική (μάλιστα ο ίδιος έδειξε πρωτοβουλία και ουσιαστικά έλυσε το μεγαλύτερο μέρος μόνος του) και πραγματικά ανυπομονώ να δουλέψουμε και σε άλλα project μαζί στο μέλλον :)

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου