1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_SSL_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ ./CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_METHOD *meth; 38 SSL_CTX *ctx; 39 #if defined(PETSC_USE_SSL_CERTIFICATE) 40 char keyfile[PETSC_MAX_PATH_LEN]; 41 PetscBool exists; 42 PetscErrorCode ierr; 43 #endif 44 45 PetscFunctionBegin; 46 if (!bio_err){ 47 SSL_library_init(); 48 SSL_load_error_strings(); 49 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 50 } 51 52 /* Set up a SIGPIPE handler */ 53 signal(SIGPIPE,sigpipe_handle); 54 55 meth = SSLv23_method(); 56 ctx = SSL_CTX_new(meth); 57 58 #if defined(PETSC_USE_SSL_CERTIFICATE) 59 /* Locate keyfile */ 60 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 61 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 62 if (!exists) { 63 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 64 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 65 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 66 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 67 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 68 } 69 70 /* Load our keys and certificates*/ 71 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 72 73 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 74 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 75 #endif 76 77 *octx = ctx; 78 PetscFunctionReturn(0); 79 } 80 81 #undef __FUNCT__ 82 #define __FUNCT__ "PetscSSLDestroyContext" 83 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 84 { 85 PetscFunctionBegin; 86 SSL_CTX_free(ctx); 87 PetscFunctionReturn(0); 88 } 89 90 #undef __FUNCT__ 91 #define __FUNCT__ "PetscHTTPSRequest" 92 /* 93 PetscHTTPSRequest - Send a request to an HTTPS server 94 95 Input Parameters: 96 + type - either "POST" or "GET" 97 . url - URL of request host/path 98 . header - additional header information, may be NULL 99 . ctype - data type of body, for example application/json 100 . body - data to send to server 101 . ssl - obtained with PetscHTTPSConnect() 102 - buffsize - size of buffer 103 104 Output Parameter: 105 . buff - everything returned from server 106 */ 107 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 108 { 109 char *request=0; 110 char contentlength[40],contenttype[80],*path,*host; 111 int r; 112 size_t request_len,len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 113 PetscErrorCode ierr; 114 PetscBool flg; 115 116 PetscFunctionBegin; 117 ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 118 ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 119 if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 120 *path = NULL; 121 ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 122 123 ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 124 ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 125 126 if (header) { 127 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 128 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 129 } 130 131 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 132 if (ctype) { 133 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 134 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 135 } 136 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 137 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 138 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 139 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 140 141 /* Now construct our HTTP request */ 142 request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 143 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 144 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 145 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 146 ierr = PetscStrcat(request,path);CHKERRQ(ierr); 147 ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 148 ierr = PetscStrcat(request,host);CHKERRQ(ierr); 149 ierr = PetscFree(host);CHKERRQ(ierr); 150 ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 151 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 152 if (ctype) { 153 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 154 } 155 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 156 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 157 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 158 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 159 160 r = SSL_write(ssl,request,request_len); 161 switch (SSL_get_error(ssl,r)){ 162 case SSL_ERROR_NONE: 163 if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 164 break; 165 default: 166 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 167 } 168 169 /* Now read the server's response, assuming that it's terminated by a close */ 170 r = SSL_read(ssl,buff,(int)buffsize); 171 len = r; 172 switch (SSL_get_error(ssl,r)){ 173 case SSL_ERROR_NONE: 174 break; 175 case SSL_ERROR_ZERO_RETURN: 176 SSL_shutdown(ssl); /* ignore shutdown error message */ 177 break; 178 case SSL_ERROR_SYSCALL: 179 break; 180 default: 181 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 182 } 183 buff[len] = 0; /* null terminate string */ 184 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 185 186 SSL_free(ssl); 187 ierr = PetscFree(request);CHKERRQ(ierr); 188 PetscFunctionReturn(0); 189 } 190 191 #undef __FUNCT__ 192 #define __FUNCT__ "PetscHTTPSConnect" 193 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 194 { 195 BIO *sbio; 196 PetscErrorCode ierr; 197 198 PetscFunctionBegin; 199 /* Connect the TCP socket*/ 200 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 201 202 /* Connect the SSL socket */ 203 *ssl = SSL_new(ctx); 204 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 205 SSL_set_bio(*ssl,sbio,sbio); 206 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 207 PetscFunctionReturn(0); 208 } 209 210